1. 程式人生 > >Hell on the Markets(貪心)

Hell on the Markets(貪心)

貪心部分的理論依據:前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。所以一定可以湊出a[k+1]-p。所以只需從之前湊出sum[k]裡面剪掉湊出a[k+1]-p的數就可以湊出sum[k]+p。所以從1~sum[k+1]都可以湊出。

輸入n個數,第i個數ai滿足1≤ai≤i。對每個數新增符號,使和值為0。

排序後從最大的數開始貪心就好。這次用了一些c++不常用的特性寫的,一開始缺了個頭檔案CE了。

#include<iostream>
#include<algorithm>
#include<iterator>
using namespace std;
const int maxn=100010;
struct q{
    int num,id;
    friend ostream& operator << (ostream &out,const q& x){
        cout<<x.num;
        return out;
    }
};
q a[maxn];
int main(){
    int n;
    while(cin>>n){
        long long sum=0;
        for(int i=0;i<n;++i){
            a[i].id=i;
            cin>>a[i].num;
            sum+=a[i].num;
        }
        if(sum&1) {cout<<"No\n";continue;}
        sum>>=1;
        sort(a,a+n,[](q& a,q& b){return a.num>b.num;});
        for(int i=0;i<n;++i){
            if(a[i].num<=sum){
                sum-=a[i].num;
                a[i].num=1;
            }
            else a[i].num=-1;
        }
        sort(a,a+n,[](q& a,q& b){return a.id<b.id;});
        cout<<"Yes\n";
        copy(a,a+n,ostream_iterator<q>(cout," "));
        cout<<endl;
    }
    return 0;
}