1. 程式人生 > >uva1614 Hell on the Markets

uva1614 Hell on the Markets

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) {return
x.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