Codeforces Round #519 by Botan Investments

Codeforces Round #519 by Botan Investments


A. Elections

#include <bits/stdc++.h>
using namespace std;
int n, mx = 0, sum = 0, x;
int main() {
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i) 
		scanf("%d",&x), sum += x, mx = max(mx, x);
	int k;
	
	for(k = mx; k <= 500; ++k) {
		if(k*n > (sum<<1)) {
			printf("%d\n",k); return 0;
		}
	}
	return 0;
}

B. Lost Array

做法:枚举k判断合法性,根据前k+1个a,求出x,再进行判断即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, cnt, b[1111];
ll a[1111], x[1111];
int ck(int k) {
	for(int i = 0; i < k; ++i) x[i] = a[i+1] - a[i];
	ll b = 0;
	for(int i = 1; i <= n; ++i) {
		b = b + x[(i-1)%k];
		if(b != a[i]) return 0;
	}
	return 1;
}
int main() {
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i)	scanf("%lld",&a[i]);
	for(int k = 1; k <= n; ++k) {
		if(ck(k)) b[++cnt] = k;
	}
	printf("%d\n",cnt);
	for(int i = 1; i<= cnt; ++i) printf("%d ",b[i]); puts("");
	return 0;
}

C. Smallest Word

做法:从前到和维护一个前i个字符能构成字典序最小的串,然后对于第i个串,需要考虑前i-1个字符形成的串,以及加入第i个字符后是否反转,转移即可。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, ans[1111];
char str[1111];
bool operator < (const string a, const string b) {
	for(int i = 0; i < a.size(); ++i) if(a[i] != b[i]) return a[i] < b[i];
	return 1;
}
string cal(string s) {
	string t = s;
	reverse(t.begin(), t.end());
	return min(t,s);
}

int main() {
	scanf("%s", str+1); n = strlen(str+1);
	string s, t1, t2, t11, t22; s += str[1];
	for(int i = 2; i <= n; ++i) {
		t1 = t2 = s;
		t1 += str[i];
		reverse(t2.begin(), t2.end()); t2 += str[i];
		t11 = t1; 	reverse(t11.begin(), t11.end());
		t22 = t2; 	reverse(t22.begin(), t22.end());	
		s = min(min(t1,t2), min(t11, t22));
		if(s == t1) continue;
		else if(s == t2) ans[i-1]^=1;
		else if(s == t11) ans[i]^=1;
		else ans[i-1]^=1, ans[i]^=1;
	}
	for(int i = 1; i <= n; ++i) printf("%d ",ans[i]); puts("");
	return 0;
}

D. Mysterious Crime

做法:贪心的满足第一个串,然后根据第一个串判断所有的串最长匹配到什么位置,匹配失败后,就将这段区间的数字的答案计算完成了。然后,继续枚举下一段即可,这样已经计算的数字一定是最优的。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, m, b[100007], pos[12][100007], p[12], a[12][100007];
bool ck() {
	if(b[a[1][p[1]]]) return 0;
	if(p[1] > n) return 0;
	for(int i = 2; i <= m; ++i) {
		if(p[i] > n || a[i][p[i]] != a[i-1][p[i-1]] || b[a[i][p[i]]]) return 0;
	}
	return 1;
}
void cal(int x) {
	int ans = 0;
	for(int i = 1; i <= m; ++i) p[i] = pos[i][x];
	while(ck()) {
		for(int i = 1; i <= m; ++i) ++p[i];
		++ans;
	}
	for(int j = pos[1][x], t = ans; t ; ++j, --t) b[a[1][j]] = t;
	return;
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= m; ++i)
		for(int j= 1; j <= n; ++j) {
			scanf("%d",&a[i][j]);
			pos[i][a[i][j]] = j;
		}

	for(int i = 1; i <= n; ++i) if(!b[a[1][i]]) {
		cal(a[1][i]);
	}
	ll ans = 0;
	for(int j = 1;j <= n; ++j) ans += 1LL*b[j];
	printf("%lld\n",ans);
	return 0;
}
/*
4 2
1 2 4 3
4 3 1 2
*/

E. Train Hard, Win Easy

做法:求$$\sum {i=1}^n \sum ^n min(a[i].x+a[j].y, a[i].y+a[j].x)$$
首先 i,j 之间不能计算的答案可以从最终的答案中减去,那么考虑如何优化掉第二维;min提醒我们可以讨论。当\(a[i].x + a[j].y <= a[i].y + a[j].x\)\(a[i].x - a[i].y <= a[j].x - a[j].y\)时最小值是\(a[i].x + a[j].y\)
排序之后分别考虑贡献即可;另一种情况,同理。可以通过预处理解决。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
typedef long long ll;
using namespace std;
int n, m, x, y;
struct node{
	ll x, y; int id;
	bool operator < (const node &a) const { return x - y < a.x - a.y; }
}a[300007];
ll ans[300007], sx[300007], sy[300007];
int main() {
	scanf("%d%d",&n,&m);
	rep(i,1,n) scanf("%lld%lld", &a[i].x, &a[i].y), a[i].id = i;
	rep(i,1,m) {
		scanf("%d%d", &x, &y);
		ans[x] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
		ans[y] -= min(a[x].x+a[y].y, a[x].y+a[y].x);
	} sort(a+1, a+1+n);
	per(i,n,1) sy[i] = sy[i+1] + a[i].y; rep(i,1,n) sx[i] = sx[i-1] + a[i].x;
	for(int num, i = 1; i <= n; ++i) {
		num = lower_bound(a+1,a+1+n,a[i])-a-1;
		ans[a[i].id] += a[i].x*(n - num - 1LL) + sy[num+1] - a[i].y + a[i].y*num + sx[num];
	}
	for(int i = 1; i<= n; ++i) printf("%lld ", ans[i]); puts("");
}

F. Make It One

做法:求至少挑多少个数可以使得他们的gcd为1。首先,可以证明最多挑7个数,因为这些数两两之间至少有一个不重复的公共素数。\(dp[i][j]\) 表示选 i 个数gcd为 j 的方案数,那么通过容斥转移就是

\[dp[i][j] = C_{num_j}^i - \sum_{k=2}^\infty dp[i][j*k] \]

\[num_j = \sum_{i=1}^n [a[i] ~mod ~j = 0] \]

即从包含j的数里挑i个的方案数,去掉包含\(j\)的倍数的方案数,这个值可能很大运算过程中取模即可。答案就是找到最小的\(i\)使得\(dp[i][1]>0\)

#include <bits/stdc++.h>
typedef long long ll;
const int N = 3e5 + 7;
const int mod = 1e9 + 7;
using namespace std;
int num[N], a[N], n, MX;
ll dp[11][N], f[N], inv[N];
ll q_pow(ll a, ll b) {
	ll ans = 1;
	while(b) {
		if(b&1) ans = (ans*a) % mod;
		a = (a*a) % mod;
		b >>= 1LL;
	}
	return ans;
}
void init() {
	f[0] = 1;
	for(int i = 1; i <= 3e5; ++i) f[i] = (f[i-1]*i) % mod;
	inv[300000] = q_pow(f[300000], mod-2);
	for(int i = 300000-1; i >= 0; --i) inv[i] = (inv[i+1]*(i+1LL)) % mod;
}
ll C(int n, int m) {
	if(m > n) return 0;
	if(m == n || !m ) return 1;
	return (f[n]*inv[m])%mod*inv[n-m]%mod;
}
void solve(int x) {
	for(int i = 1; i*i <= x; ++i) if(x % i == 0) {
		++num[i];
		if(i*i == x) continue;
		++num[x/i];
	}
}
int main() {
	init();
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i) 
		scanf("%d", &a[i]), solve(a[i]), MX = max(MX,a[i]);
	for(int i = 1; i <= 7; ++i) {
		for(int j = MX; j >= 1; --j) {
			dp[i][j] = C(num[j],i);
			for(int k = j+j; k <= MX; k += j) {
				dp[i][j] -= dp[i][k];
				if(dp[i][j] < 0) dp[i][j]+=mod;
				dp[i][j] %= mod;
			}
		}
		if(dp[i][1] > 0) {
			printf("%d\n",i); return 0;
		}
	}
	puts("-1");
	return 0;
}

G. Speckled Band

做法:略猛,有缘再写了。。。

posted @ 2018-11-02 19:50  RRRR_wys  阅读(267)  评论(0编辑  收藏  举报