zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",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
    ",ans);
    	return 0;
    }
    /*
    4 2
    1 2 4 3
    4 3 1 2
    */
    

    E. Train Hard, Win Easy

    做法:求$$sum {i=1}^n sum{j=1,j != i,can[i][j] = 0} ^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
    ",i); return 0;
    		}
    	}
    	puts("-1");
    	return 0;
    }
    

    G. Speckled Band

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

  • 相关阅读:
    The library 'hostpolicy.dll' required to execute the application was not found in
    矩阵乘法
    2019-11-1
    四边形不等式的应用
    2019-10-30
    2019-10-29
    差分与前缀和
    平衡树SPLAY
    可爱的树链剖分(染色)
    cable tv network
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9898128.html
Copyright © 2011-2022 走看看