zsyzlzy

导航

 

在这里插入图片描述

思路:背包+逆推。

很明显可以发现:
t=a1a2+i=3n±ait=a_1-a_2+\sum\limits_{i=3}^n\pm a_i
所以我们定义背包数组f[i][j]ijif[i][j](1,1)f[i][j]表示前i个数的和为j,且第i个数的符号为f[i][j](1为正,-1为负)

这道题的难点是逆推操作位置。
以下正负数都是指添了±\pm号之后的数
可以发现,第3个数以后的一段连续的正数前面一定是一个负数。
形如:a+b+c+d+e-a+b+c+d+e……(字母均表示正数)
则有:a+b+c+d+e=(abcde)-a+b+c+d+e……=-(a-b-c-d-e-……)(负负得正)
所以,我们可以先把连续正数及其前面的那一个数合并起来,最后减去剩余的数即可。
具体的,顺序扫描数组,isi(s++)1,i(++s)若第i个数为正数,且s为前面所作的减操作次数,则当前的操作位置为i-(s++)-1,即i-(++s)

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110,X=10000;
int n,m,s;
char f[N][2*X+5],o[N],a[N];
int main() {
	scanf("%d %d",&n,&m); m+=X;
	for(int i=1,x;i<=n;i++)scanf("%d",&x),a[i]=x;
	f[2][a[1]-a[2]+X]=-1;s=abs(a[1]-a[2]);
	for(int i=3;i<=n;s+=a[i++])
		for(int j=-s;j<=s;j++)
			if(f[i-1][j+X]) {
				f[i][j+a[i]+X]=1;
				f[i][j-a[i]+X]=-1;
			}
	for(int i=n;i>1;i--)
		m-=(o[i]=f[i][m])*a[i];
	s=0;
	for(int i=3;i<=n;i++)
		if(o[i]==1)
			printf("%d\n",i-++s);
	while(++s<n)puts("1");
	return 0;
}
posted on 2019-10-24 09:28  zsyzlzy  阅读(120)  评论(0编辑  收藏  举报