uva1614 Hell on the Markets
阿新 • • 發佈:2018-10-05
style esp ons sin ont cst urn div nbsp
貪心部分的理論依據:前i個數可以湊出1~sum[i]的所有整數。
證明:第二類數學歸納,n=1時成立,假設n=k之前所有項都成立,當n=k+1時。sum[k+1]=sum[k]+a[k+1]。
只需證明能湊出sum[k]+1~sum[k+1]間的整數即可。設1≤p≤a[k+1],sum[k]+p=sum[k]+a[k+1]-(a[k+1]-p)。
因為1≤a[i]≤i,易得sum[k]≥k,a[k+1]-p≤k。又因為已知前k個數可以湊出1~sum[k],所以一定可以湊出a[k+1]-p。
所以只需從之前湊出sum[k]裏面剪掉湊出a[k+1]-p的數就可以湊出sum[k]+p。所以從1~sum[k+1]都可以湊出。
實現就是輸入時存一下sum,若為奇數就無解,否則再排個序,從大到小掃一遍,選湊成和為sum/2的數的符號為+,其余為-。
先排序,從大到小減(不然會多減小的)
註意sum 用 ll
#include<cstdio> #include<cstdlib> #include<algorithm> #include<iostream> using namespace std; const int maxn=100005; struct node{ int x,id; } a[maxn]; int ans[maxn]; bool cmp(node x,node y) {returnx.x>y.x;} int main() { int n; int sum; while (scanf("%d",&n)==1) { long long 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]); cout<<endl; } return 0; }
uva1614 Hell on the Markets