原题连接

题目描述

给定一个整数数组\(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. 如何用markdown绘制flow流程图

  2. Buffer与Cache的理解

    Linux与Windows内存Linux系统的内存机制是优先使用物理内存,当物理内存还有空闲时,Linux系统是不会释放内存的,即使使用过内存的程序已经被关闭,这部分内存就用来做缓存了.换句话说,即使 ...

  3. Prometheus + Grafana 监控 Redis

    Prometheus安装 .linux-amd64.tar.gz .linux-amd64. cd /prometheus # Start Prometheus. # By default, Prom ...

  4. IDEA安装Git

    1.下载Git 官方地址为:https://git-scm.com/download/win 2.下载完之后,双击安装 3.选择安装目录 4.选择组件 5.开始菜单目录名设置 6.选择使用命令行环境 ...

  5. table+ajax加载数据

    //ajax加载notice $(function() { //${pageContext.request.contextPath}/ /** var res = [ {noticeTitle:'必答 ...

  6. PHP以星号隐藏用户名手机号码和邮箱实例

    一款简单实用的PHP以星号隐藏用户名手机号码和邮箱实例,将用户的一些文字信息隐藏一部分用星号代替,以便于保护用户隐私. 隐藏函数: function hideStar($str) { //用户名.邮箱 ...

  7. 【hash表】图书管理

    [哈希和哈希表]图书管理 题目描述 图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入.为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一 ...

  8. golang 客户端

    package main import ( "fmt" "io/ioutil" "net/http" ) func main() { fmt ...

  9. 输出单项链表中倒数第k个结点——牛客刷题

    题目描述: 输入一个单向链表,输出该链表中倒数第k个结点 输入.输出描述: 输入说明:1.链表结点个数 2.链表结点的值3.输入k的值 输出说明:第k个结点指针 题目分析: 假设链表长度为n,倒数第k ...

  10. websocket vue

    /* eslint-disable */ let tt; let count = 1; let lockReconnect = false; function isJsonString(str) { ...