题意:n个数分别为a[i],问是否存在一组对应的b[i],b[i]=1 || b[i]=-1,使得ai*bi的n项和为0。
题解:
先证明一个结论吧,对于1≤ai≤i+1,前面ai个数一定可以凑出1~sum[i]中的任意一个数.
对于i=1显然成立,假设对于i=k结论成立,那么对于i=k+1来说,只要证明sum[k]+i,1≤i≤ak+1可以凑出来就行了。
因为sum[k]+i≥k+1,且1≤ak+1≤k+1,所以可以先选一个ak+1,剩下的0≤sum[k]+i-ak+1≤sum[k]一定是可以由前面的数字凑出来的。
这就证明了贪心的正确性。
转自:http://www.cnblogs.com/jerryRey/p/4702658.html
代码中这个cmp也可以换成
用结构体存id,val 再写两个cmp排序就好了。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 1e5+5; int a[maxn]; int r[maxn]; int n; long long sum; bool cmp(int x,int y) //这个cmp的思想要会 { return a[x]<a[y]; } void init() { sum=0; memset(a,0,sizeof(a)); memset(r,0,sizeof(r)); } int main() { freopen("hell.in","r",stdin); freopen("hell.out","w",stdout); while(scanf("%d",&n)!=EOF) { init(); for(int i=0;i<n;i++) { scanf("%d",&a[i]); sum+=a[i]; r[i]=i; } sort(r,r+n,cmp); if(sum%2==1) puts("No"); else { puts("Yes"); sum>>=1; //cout<<sum<<endl; for(int i=n-1;i>=0;i--) { if(a[r[i]]<=sum) { sum-=a[r[i]]; a[r[i]]=1; } else a[r[i]]=-1; //注意这里改变的是a数组不是r数组 } for(int i=0;i<n-1;i++) printf("%d ",a[i]); printf("%d ",a[n-1]); } } return 0; }