uva 1614奇怪的股市(归纳法证明,贪心)
uva 1614奇怪的股市(歸納法證明,貪心)
輸入一個長度為n的序列a,滿足\(1\le a_i\le i\),要求確定每個數的正負號,使得所有數的總和為0.例如a={1, 2, 3, 4},則4個數的符號分別是1, -1, -1, 1即可。但若a={1, 2, 3, 3},則無解。n<=1e5。
這道題相當于要找到兩堆相等的數。若序列中數的總和為奇數,那么拆出來的兩堆數無論如何都不可能相等,所以無解。由于這道題的特殊性質,可用歸納法證明總和為偶數時一定有解。
現在要證明,用前i個數的全部或部分可以湊出0到sum[i]的所有整數。n=1時這是成立的。假設n=k之前所有項都成立,那么\(sum[k+1]=sum[k]+a[k+1]\)。只需證明能湊出\(sum[k]+1\)到\(sum[k]+a[k+1]\)的所有整數即可。由于\(1\le a_[k+1]\le k+1\),而\(sum[k]\ge k\),所以\(sum[k]+p=x+a[k+1]\ (1\le p\le a[k+1],0\le x\le sum[k])\)恒成立。
這樣一來,就證明了用前n個數,可以湊出sum[n]/2。當sum[n]是偶數時,另一半也就是sum[n]/2。現在的問題就是找出和等于sum[n]/2的數。直接將a數組從大到小排序,然后貪心的取即可。
為什么貪心的取是正確的呢?因為\(1\le a_i\le i\),排序完的數組必定也滿足這個條件。所以只要貪心的取顯然有解。
#include <cstdio> #include <algorithm> using namespace std;const int maxn=1e5+5; struct node{int data, id; }a[maxn]; int n, chose[maxn]; long long sum;bool cmp1(node &x, node &y){return x.data>y.data; }//100萬才需要讀優 int main(){while (~scanf("%d", &n)){sum=0;for (int i=0; i<n; ++i){scanf("%d", &a[i].data);sum+=a[i].data; a[i].id=i;}if (sum&1){puts("No"); continue; }else sum>>=1;sort(a, a+n, cmp1);for (int i=0; i<n; ++i)if (a[i].data<=sum){sum-=a[i].data;chose[a[i].id]=1;} else chose[a[i].id]=-1;puts("Yes");for (int i=0; i<n; ++i)printf("%d ", chose[i]);puts("");}return 0; }轉載于:https://www.cnblogs.com/MyNameIsPc/p/8495362.html
總結
以上是生活随笔為你收集整理的uva 1614奇怪的股市(归纳法证明,贪心)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 生产异常处理流程
- 下一篇: Angular动态表单生成(八)