UVA 1614 Hell on the Markets

https://vjudge.net/problem/UVA-1614

题目

金融危机中有的银行倒闭,有的被其他银行收购。危机快结束时,只剩下了两家银行继续运转,虽然市场仍然停业,但是新出台的政策正在鼓励市场逐渐开张。为了避免投机行为,同时为了鼓励市场复苏,只允许人们在一个金融机构中交易,并且第 $i$ 分钟交易量不能超过 $i$ 笔。

两个银行决定和政府合作刺激市场复苏。银行的董事会已经对第一次交易时段中每分钟的交易量达成一致。其中一个银行会在第 $i$ 分钟买入 $a_i$ 份合约,另外一个银行就卖出 $a_i$ 份合约。他们不关心到底是买入还是卖出,因为旁观者只能看到每分钟的交易量。他们仅仅关心如何降低自己的风险,在这个交易时段结束的时候自己不要有多余的合约。我们定义 $b_i=1$ 为第一个银行在第 $i$ 分钟买入合约, $b_i=-1$ 为第二个银行在第 $i$ 分钟买入合约(此时第一个银行卖出合约),那么要求就是这个交易时段中需要满足 $\sum\limits_{i = 1}^n {{a_i}{b_i}}  = 0$。

你们所在的三人团队非常幸运,挺过了这次金融危机,并且银行对你们团队所在的数据中心开放了数据。你们的任务是找出这样的 $b_i$ ,如果不可能找出就报告。

题解

需要证明:对于任意的$1 \leqslant x \leqslant S_i$ ($S_i$ 为 ${a_i}$ 前 $i$ 项的和),都能从前 $i$ 项中选 $j$ ($1\leqslant 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$ ($1\leqslant j \leqslant i$)个数,使他们的和为 $x$。

P(1)显然成立……

要使P(i)对任意的i成立,用第二数学归纳法,需假设P(1),P(2),P(3),...,P(k-1)成立,并证明P(k)也成立。

即对任意的 $x\in[1,S_k]$ ,都能选出j个数使和为 $x$。

因为P(k-1)成立,可以不选第$k$个数,所以只需证明对任意的 $x\in[S_{k-1}+1,S_k]$ ,都能选出j个数使和为 $x$。

设 $1\leqslant p\leqslant a_k$,使

\[S_{k-1}+p = S_{k}-(a_k-p)\]

成立

因 $0\leqslant a_k-p \leqslant k-1$ ,又P(1),P(2),P(3),...,P(k-1)都成立,所以一定存在一种前k-1个数选择使它们的和为 $a_k-p$,只需去掉这些数就可以凑出任意的 $x\in[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\n");
			continue;
		}
		printf("Yes\n");
		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('\n');
	}
	return 0;
}

重新拉动经济增长

猜你喜欢

转载自www.cnblogs.com/sahdsg/p/10525618.html
今日推荐