https://vjudge.net/problem/UVA-1614
题目
金融危机中有的银行倒闭,有的被其他银行收购。危机快结束时,只剩下了两家银行继续运转,虽然市场仍然停业,但是新出台的政策正在鼓励市场逐渐开张。为了避免投机行为,同时为了鼓励市场复苏,只允许人们在一个金融机构中交易,并且第 $i$ 分钟交易量不能超过 $i$ 笔。
两个银行决定和政府合作刺激市场复苏。银行的董事会已经对第一次交易时段中每分钟的交易量达成一致。其中一个银行会在第 $i$ 分钟买入 $a_i$ 份合约,另外一个银行就卖出 $a_i$ 份合约。他们不关心到底是买入还是卖出,因为旁观者只能看到每分钟的交易量。他们仅仅关心如何降低自己的风险,在这个交易时段结束的时候自己不要有多余的合约。我们定义 $b_i=1$ 为第一个银行在第 $i$ 分钟买入合约, $b_i=-1$ 为第二个银行在第 $i$ 分钟买入合约(此时第一个银行卖出合约),那么要求就是这个交易时段中需要满足 $sumlimits_{i = 1}^n {{a_i}{b_i}} = 0$。
你们所在的三人团队非常幸运,挺过了这次金融危机,并且银行对你们团队所在的数据中心开放了数据。你们的任务是找出这样的 $b_i$ ,如果不可能找出就报告。
题解
需要证明:对于任意的$1 leqslant x leqslant S_i$ ($S_i$ 为 ${a_i}$ 前 $i$ 项的和),都能从前 $i$ 项中选 $j$ ($1leqslant j leqslant i$)个数,使他们的和为 $x$。
出自:https://wcr1996.com/2015/02/26/uva-1614-hell-on-the-markets/
证明需要用第二数学归纳法
设P(i)为对于任意的$1 leqslant x leqslant S_i$ ($S_i$ 为 ${a_i}$ 前 $i$ 项的和),都能从前 $i$ 项中选 $j$ ($1leqslant j leqslant i$)个数,使他们的和为 $x$。
P(1)显然成立……
要使P(i)对任意的i成立,用第二数学归纳法,需假设P(1),P(2),P(3),...,P(k-1)成立,并证明P(k)也成立。
即对任意的 $xin[1,S_k]$ ,都能选出j个数使和为 $x$。
因为P(k-1)成立,可以不选第$k$个数,所以只需证明对任意的 $xin[S_{k-1}+1,S_k]$ ,都能选出j个数使和为 $x$。
设 $1leqslant pleqslant a_k$,使
[S_{k-1}+p = S_{k}-(a_k-p)]
成立
因 $0leqslant a_k-p leqslant k-1$ ,又P(1),P(2),P(3),...,P(k-1)都成立,所以一定存在一种前k-1个数选择使它们的和为 $a_k-p$,只需去掉这些数就可以凑出任意的 $xin[S_{k-1}+1,S_k]$ 。
接下来就是凑解了……
一定存在这样的选择,那么我们就凑sum/2……
显然sum为奇数时凑不出来
从大到小找出一个小于等于当前和的数后,将和减去这个数可以得到新的和
之前证明了一定可以凑出新的和,于是可以继续减……
第一次见到第二数学归纳法,还是记下……
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") #include<bits/stdc++.h> using namespace std; #define REP(r,x,y) for(register int r=(x); r<(y); r++) #define REPE(r,x,y) for(register int r=(x); r<=(y); r++) #ifdef sahdsg #define DBG(...) printf(__VA_ARGS__) #else #define DBG(...) #endif #define MAXN 100007 struct node { int x, id; }arr[MAXN]; inline bool cmp(const node& l, const node& r) { return l.x>r.x; } bool ans[MAXN]; int main() { int t; while(~scanf("%d", &t) && t) { long long sum = 0; memset(ans,0,sizeof ans); REP(i,0,t) { scanf("%d", &arr[i].x); arr[i].id=i; sum += arr[i].x; } sort(arr,arr+t,cmp); if(sum&1) { printf("No "); continue; } printf("Yes "); sum>>=1; REP(i,0,t) { if(arr[i].x<=sum) { sum-=arr[i].x; } else { ans[arr[i].id]=1; } } REP(i,0,t) { if(i) putchar(' '); if(ans[i]) printf("-1"); else printf("1"); } putchar(' '); } return 0; }
重新拉动经济增长