原题连接

题目描述

给定一个整数数组\(a_1,a_2,…,a_n\)。

定义数组第 i 位上的减操作:把\(a_i\)和\(a_{i+1}\)换成\(a_i - a_{i+1}\)。

用con(a,i)表示减操作,可以表示为:

\[con(a,i)=[a_1,a_2,…,a_{i-1},a_i-a_{i+1},a_{i+2},…,a_n]
\]

长度为 n 的数组,经过 n-1 次减操作后,就可以得到一个整数t。

例如数组[12,10,4,3,5]经过如下操作可得到整数4:

\[con([12,10,4,3,5],2) = [12,6,3,5]
\\
con([12,6,3,5] ,3) = [12,6,-2]
\\
con([12,6,-2] ,2) = [12,8]
\\
con([12,8] ,1) = [4]
\]

现在给定数组以及目标整数,求完整操作过程。

输入格式

第1行包含两个整数n和t。

第2..n+1行:第i行包含数组中的第 i 个整数\(a_i\)。

输出格式

输出共n-1行,每行包含一个整数,第 i 行的整数表示第 i 次减操作的操作位置。

数据范围

\[1 \le n \le 100 \\
-10000 \le t \le 10000 \\
1 \le a_i \le 100 \\
\]

输入样例:

5 4
12
10
4
3
5

输出样例:

2
3
2
1

解题报告

题意理解

就是说,有一种操作,名为减操作,可以将合并相邻的两个数,比如说原来的数字是.

\[3,4,那么合并后变成-1
\]

也就是,

\[合并后的数字=前面一个数字-后面一个数字. \\
a[i]=a[i]-a[i-1] \\
然后删除a[i+1]
\]


思路解析

性质分析

我们发现,每一次减操作都会使得序列长度减少一个.

\[即原本长度len,然后一次减操作后就会变成len-1
\]

所以说,我们发现其实对于序列的最终结果\(t\),可以变成这种形式.

\[a[1]-a[2] \pm a[3] \pm a[4] \pm a[5]=t
\]

举个例子表示一下

\[a[1] \quad a[2] \quad a[3] \quad a[4] \quad a[5] \qquad 原序列\\
a[1] \quad a[2]-a[3] \quad a[4] \quad [5] \qquad 此时cut(2) \\
a[1] \quad a[2]-a[3] \quad a[4]-a[5] \qquad 此时cut(3) \\
a[1] \quad a[2]-a[3]-(a[4]-a[5]) \qquad 此时cut(2) \\
a[1]-(a[2]-a[3]-(a[4]-a[5])) \qquad 最后cut(1) \\
a[1]-a[2]+a[3]+a[4]-a[5] \qquad 处理后的答案序列
\]

我们发现

\[a[1]必须是+号,a[2]必须是-号
\]

对于

\[a[1]必须是+号
\]

因为我们发现,\(1\)的前面没有数,可以去进行减操作.

最后一次执行的必然是\(cut(1)\)操作

\(a[1]\)表示,我真的想要减操作,但是我就是没有数可以和我一起减操作.

然后我们再来康康为什么一定是

\[a[2]必须为-号
\]

其实道理和之前一样,

最后一次执行的必然是\(cut(1)\)操作.

\(a[2]\)表示,我真的是被迫的,\(cut(1)\)使得\(a[1]-a[2]\).


状态设置

这样我们将题目转换成了

一个数列,对于数组中的数,将一些正整数变为负数,使整个数组的和为t,最后输出将哪些数变为负数.

我们发现这道题目的数据范围

\[n \le 100 \\
-10000 \le t \le 10000 \\
\]

数据范围真的好小啊,开一个\(n*t\)的数据范围丝毫没有问题.

所以说我们不妨这么设置一个状态数组.

\[f[i][cnt] \quad 表示前i个数字的和为cnt \\
f[i][cnt]=1 \quad 表示第i个数前面是+号 \\
f[i][cnt]=-1 \quad 表示第i个数前面是-号 \\
\]

不过我们要注意一下,C++负数下标有可能性挂掉了,所以我们不得不让所有下标加上一个固定的大数字,保证最后的下标是一个正数.

此时最大的问题就是,如何反推出我们的cut操作?


反推路径
  1. 为什么有些数可以是正数?也就是前面是+号?

这是一个非常重要的问题,我们发现.

\[一个数字前面是+号,只有在它这一位进行cut操作.
\]

假如说我们第\(i\)位不进行\(cut\)操作,那么它前面一定不是\(+\)号.

一个数,前面不是加号,就是减号.

\[cut(i) \qquad a[i]-a[i+1] \\
cut(i-1) \qquad a[i-1]-a[i] \\
\]

只有当\(i-1\)位进行\(cut\)操作的时候,这个第\(i\)位才可以是减号.

这就让我们证明了.

\[一个数字前面是+号,只有在它这一位进行cut操作.
\]

所以找到每一个\(+\)号的位置,然后输出当前位置.

不过你要注意一下,输出应该是.

\[i-tot-1 \\
tot表示为当前有几个cut操作了 \\
\]


代码解析

#include<bits/stdc++.h>
using namespace std;
#define init() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);//读入优化
const int maxn=105,maxt=20086,hh=10000;//hh是我们的下标转移常数
int n,t,f[maxn][maxt],a[maxn],ans[maxn];
void dp()
{
f[1][a[1]+hh] = 1;//a[1]必然是正数
f[2][a[1]-a[2]+hh]=-1;//a[2]必然是
for(int i=3; i<=n; i++)
for(int j=-10000+hh; j<=10000+hh; j++)
{
if(f[i-1][j])//可以转移
{
f[i][a[i]+j]=1;//+号
f[i][j-a[i]]=-1;//-号
}
}
}
void out()
{
int s=hh+t;
for(int i=n; i>=2; i--)//回溯走路径,确定+,-号
{
ans[i]=f[i][s];
if(ans[i]==1)
s-=a[i];
else if(ans[i]==-1)
s+=a[i];
}
int cnt=0;
for(int i=2; i<=n; i++)
if(ans[i]==1)//是时候减操作了.
{
cout<<i-cnt-1<<endl;
cnt++;
}
for(int i=2; i<=n; i++)
if(ans[i]==-1)//寻找
cout<<1<<endl;
}
int main()
{
init();
cin>>n>>t;
for(int i=1; i<=n; i++)
cin>>a[i];
dp();
out();
return 0;
}

POJ1722 算法竞赛进阶指南 SUBSTRACT减操作的更多相关文章

  1. 算法竞赛进阶指南0x51 线性DP

    AcWing271. 杨老师的照相排列 思路 这是一个计数的题目,如果乱考虑,肯定会毫无头绪,所以我们从1号到最后一个依次进行安排. 经过反复实验,发现两个规律 每一行的同学必须是从左向右依次连续放置 ...

  2. 算法竞赛进阶指南0x35高斯消元与线性空间

    高斯消元 目录 高斯消元 ACWing207. 球形空间产生器(点击访问) 求解思路 代码 ACWing208. 开关问题(点击访问) 思路 代码 总结 欣赏 线性空间 定义 ACWing209. 装 ...

  3. 算法竞赛进阶指南0x34矩阵乘法

    文章目录 矩阵的相关性质再回顾 矩阵加速大法: ACWing205. 斐波那契 代码 ACWing206. 石头游戏 解题思路: 感受: 代码 矩阵的相关性质再回顾 对于一个矩阵 满足结合律 满足乘法 ...

  4. 《算法竞赛进阶指南》0x10 基本数据结构 Hash

    Hash的基本知识 字符串hash算法将字符串看成p进制数字,再将结果mod q例如:abcabcdefg 将字母转换位数字(1231234567)=(1*p9+2*p8+3*p7+1*p6+2*p5 ...

  5. 《算法竞赛进阶指南》1.4Hash

    137. 雪花雪花雪花 有N片雪花,每片雪花由六个角组成,每个角都有长度. 第i片雪花六个角的长度从某个角开始顺时针依次记为ai,1,ai,2,-,ai,6. 因为雪花的形状是封闭的环形,所以从任何一 ...

  6. bzoj 1787 && bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

    题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通 ...

  7. POJ1639 算法竞赛进阶指南 野餐规划

    题目描述 原题链接 一群小丑演员,以其出色的柔术表演,可以无限量的钻进同一辆汽车中,而闻名世界. 现在他们想要去公园玩耍,但是他们的经费非常紧缺. 他们将乘车前往公园,为了减少花费,他们决定选择一种合 ...

  8. 算法竞赛进阶指南 0x00 基本算法

    放在原来这个地方不太方便,影响阅读体验.为了读者能更好的刷题,另起一篇随笔. 0x00 基本算法 0x01 位运算 [题目][64位整数乘法] 知识点:快速幂思想的灵活运用 [题目][最短Hamilt ...

  9. 算法竞赛进阶指南--快速幂,求a^b mod p

    // 快速幂,求a^b mod p int power(int a, int b, int p) { int ans = 1; for (; b; b >>= 1) { if (b &am ...

随机推荐

  1. VS Code 的插件位置更改

    --extensions-dir 你的目标文件夹 原来的目标位置:"E:\Program Files\VSCode\Code.exe" 更改后的位置:"E:\Progra ...

  2. 转 - JS 中 call 和 apply 以及 bind 的区别

    转自 https://blog.csdn.net/wyyandyou_6/article/details/81488103

  3. Ingreslock后门漏洞

    一.简介 1524端口 ingreslock Ingres 数据库管理系统(DBMS)锁定服务 利用telnet命令连接目标主机的1524端口,直接获取root权限. Ingreslock后门程序监听 ...

  4. pubwin扫描安装

    1,注意顺序 先安装一代 FS533 2,在安装精伦 3,在重新注册 PUBWIN 如果还不行一般是注册商没给注册好

  5. Centos修改时间

    1. 普通用户 a. 获取超级用户root权限 命令:su或者su -或者su - root b. passwd 用户名 2. 超级用户 a. 打开system-auth文件 命令:vi /etc/p ...

  6. (一)C++入门——指针与数组——Expression: _CrtIsValidHeapPointer(Block)

    最近在入门c++,在看<c++ Primer Plus>一书.书中P106提到,删除使用New创建的数组时,是将指针重新指到第一个元素后,再进行的删除操作.代码如下: int *ptest ...

  7. linux下selenium+phantomjs环境

    # 安装依赖软件yum -y install wget fontconfig # 下载PhantomJSwget -P /tmp/ https://bitbucket.org/ariya/phanto ...

  8. MyBatis学习存档(1)——入门

    一.简介 MyBatis的前身是iBatis,本是Apache的一个开源的项目 MyBatis是一个数据持久层(ORM)框架,把实体类和SQL语句之间建立了映射关系,是一种半自动化的ORM实现 MyB ...

  9. 怎样将当前节点从DOM树中移除

    1. 获取到当前节点. 2. 获取到当前节点的父节点. 3. 使用 Node.prototype.removeChild() 移除当前节点. <!DOCTYPE html> <htm ...

  10. 9.bash历史的交互使用

    9.历史的交互使用本章从用户的角度介绍了如何使用 GNU 的历史库功能.可以把这里的内容作为用户指南.关于如何在其它程序中使用 GNU 的历史库功能,请参考<GNU Readline 库参考手册 ...