题意:有一个长度为N的序列A,满足1≤Ai≤i,每个数的正负号不知。请输出一种正负号的情况,使得所有数的和为0。(N≤100000)
前i个数可以凑出1~sum[i]的所有整数。sum[i]为前i项之和,归纳法可证,又因为每个元素要么+1,要么-1,所以所有的元素之和必须是偶数,最后就是选择的问题了,值从大到小排序,并记录下标,依次去判断就好了,至于为什么从大到小去选取是对的,直观上感觉是这样,但不知怎么去证明,还望看到此篇文章的人可以指点一下。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100010;
struct node{int x,id;}a[N];
int b[N],ans[N];
bool cmp(node x,node y) {return x.x>y.x;}
int main()
{
int n;
long long sum;//不能用int
while (~scanf("%d",&n))
{
sum=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i, sum+=a[i].x;
}
if (sum%2) {printf("No\n");continue;}
printf("Yes\n");
sum/=2;
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++)
{
if (a[i].x<=sum) ans[a[i].id]=1,sum-=a[i].x;
else ans[a[i].id]=-1;
}
printf("%d",ans[1]);
for (int i=2;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}