zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 116

    AtCoder Regular Contest 116

    逊吔,只会ABC。

    A - Odd vs Even

    (T(1le Tle 2 imes 10^5)) 组测试数据,每次询问一个正整数 (N(1le Nle 2 imes 10^{18})) 的奇数因子多还是偶数因子多。


    打表可得

    算了证一下
    (N=4k+r)

    • (r = 2) 时,(N=4k+2=2(2k+1))
      偶数因子有2 和 (2(2k+1)) ,奇数因子有 (1)(2k+1)
      (d|(2k+1))(d) 不是 1 和 (2k+1)(d) 一定为奇数,且同时会贡献 (2d) 这一偶数因子
      所以一定是Same
    • (r = 0) 时,(N=4k)
      偶数因子个数至少是奇数因子的两倍
    • (r=1)(3) 时,
      偶数因子为 0 个,奇数因子至少 2 个
    const int N = 50 + 10, inf = 0x3f3f3f3f;
    void init(){
    	return;
    }
    void solve(){
    	int t; scanf("%d", &t);
    	while(t--){
    		ll n;
    		scanf("%lld", &n);
    		if(n % 4 == 0) puts("Even");
    		else if(n % 4 == 2) puts("Same");
    		else puts("Odd");
    	}
    	return;
    }
    int main(){
    	init(); solve();
    	return 0;
    }
    /*
    Even
    Odd
    Same
    Odd
    */
    

    B - Products of Min-Max

    给出一个包含 (n) 个数的序列 (A),有 (2^n-1)(A) 的非空子序列 (B)

    (sum max(B) imes min(B))


    从小到大排序

    [ans=sum_{i = 1}^nsum_{j = i +1} ^n {a_i imes a_j imes 2^{j-i+1}}+sum_{i = 1}^n a_i imes a_i\ =sum_{i = 1}^n a_i (sum_{j = i +1} ^n { imes a_j imes 2^{j-i+1}})+sum_{i = 1}^n a_i imes a_i\ 令f(i) = sum_{j = i +1} ^n {a_j imes 2^{j-i+1}}\ f(i-1)=sum_{j = i } ^n {a_j imes 2^{j-i}}\ f(i) = 2 imes f(i+1) + a_i ]

    即可 (O(n)) 计算答案。

    const int N = 2e5 + 10, inf = 0x3f3f3f3f, mod = 998244353;
    int n, a[N];
    void init(){
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i++)
    		scanf("%d", &a[i]);
    	sort(a + 1, a + n + 1);
    	return;
    }
    void solve(){
    	int ans = 0;
    	for(int i = n, ret = 0; i >= 1; i--){
    		ans = (ans + 1ll * a[i] * a[i] % mod) % mod;
    		ans = (ans + 1ll * a[i] * ret % mod) % mod;
    		ret = (2ll * ret % mod + a[i]) % mod;
    	}
    	printf("%d
    ", ans);
    	return;
    }
    int main(){
    	init(); solve();
    	return 0;
    }
    

    C - Multiple Sequences

    给出 (n(1le n le 2e5))(m(1le m le 2e5)),询问有多少满足条件的长度为 (n) 的序列 (A)

    • (1le A_i le M(i = 1,2,...,N))
    • (A_{i+1})(A_i) 的倍数 ((i = 1,2,...,N-1))

    注意到如果每次都有改变,顶多有 (19) 个数。调和级数一下是 (O(nlog n))

    先dp方案数。

    枚举有(i)个不同的数,对答案的贡献为 (C(n-1, i-1)*sum_{j = 1}^m dp[i][j])

    第一个肯定是第一个,不用选。

    const int N = 2e5 + 10, K = 25, inf = 0x3f3f3f3f, mod = 998244353;
    int n, m, f[K][N], fac[N], ifac[N];
    int power(int x, int y){
    	int ret = 1;
    	while(y){
    		if(y & 1) ret = 1ll * ret * x % mod;
    		x = 1ll * x * x % mod; y >>= 1;
    	}
    	return ret;
    }
    void init(){
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++) f[1][i] = 1;
    	for(int i = 2; i <= 19; i++)
    		for(int j = 1; j <= m; j++)
    			for(int k = 2; 1ll * j * k <= m; k++)
    				f[i][j * k] = (f[i][j * k] + f[i - 1][j]) % mod;
    	fac[0] = ifac[0] = 1;
    	for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
    	ifac[n] = power(fac[n], mod - 2);
    	for(int i = n - 1; i >= 1; i--) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    	return;
    }
    int C(int x, int y){
    	return 1ll * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
    }
    void solve(){
    	int ans = 0;
    	for(int i = 1; i <= min(19, n); i++){
    		int ret = 0;
    		for(int j = 1; j <= m; j++)
    			ret = (ret + f[i][j]) % mod;
    		ans = (ans + 1ll * ret * C(n - 1, i - 1) % mod) % mod;
    	}
    	printf("%d
    ", ans);
    	return;
    }
    int main(){
    	init(); solve();
    	return 0;
    }
    

    D - I Wanna Win The Game

    给出 (n(1le n le 5000)(m(1le m le 5000)),询问有多少满足条件的长度为 (n) 的序列 (A)

    • (sum_{i} A_i=m)
    • ({Xor}(A_i) =0)
    • (A_ige 0)

    显然每一位都有偶数个数选择。

    (f[i]) 表示 (n) 个数和为 (i) 的方案数

    (f[i] += C(n, 2*j) * f[(i - 2 *j) /2])

    是将之前和为 ((i - 2 imes j)/2) 的 n 个数左移一位,并选 (2 imes j) 个数最后一位为1

    const int N = 5000 + 10, mod = 998244353;
    int n, m, fac[N], ifac[N], f[N];
    int power(int x, int y){
    	int ret = 1;
    	while(y){
    		if(y & 1) ret = 1ll * ret * x % mod;
    		x = 1ll * x * x % mod; y >>= 1;
    	}
    	return ret;
    }
    void init(){
    	scanf("%d%d", &n, &m);
    	fac[0] = ifac[0] = 1;
    	for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
    	ifac[n] = power(fac[n], mod - 2);
    	for(int i = n - 1; i >= 1; i--) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    	return;
    }
    int C(int x, int y){
    	return 1ll * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
    }
    void solve(){
    	f[0] = 1;
    	for(int i = 1; i <= m; i++){
    		if(i % 2) continue;
    		for(int j = 0; j <= m && i - 2 * j >= 0; j++)
    			f[i] = (f[i] + 1ll * C(n, 2 * j) * f[(i - 2 * j) / 2] % mod) % mod;
    	}
    	printf("%d
    ", f[m]);
    	return;
    }
    int main(){
    	init(); solve();
    	return 0;
    }
    

    E - Spread of Information

    (n(1le n le 2e5)) 个点,选择 (k) 个为初始感染点,每秒沿边传播(扩张),求最快时间。


    二分最快时间(距离)

    (f_u) (u)子树内离他最近的感染点的距离
    (g_u) (u)子树内离他最远的非感染点的距离

    如果通过根节点中转能帮上 (g_u) 那么一定整个子树都已被覆盖

    其他情况,如果 (g_u= mid)(u) 必须成为初始感染点

    const int N = 2e5 + 10, inf = 0x3f3f3f3f;
    int n, k, mid, ret, f[N], g[N];
    int e, hd[N], to[N << 1], nxt[N << 1];
    void add(int u, int v){
    	to[++e] = v; nxt[e] = hd[u]; hd[u] = e;
    }
    void init(){
    	scanf("%d%d", &n, &k);
    	for(int i = 1, u, v; i < n; i++)
    		scanf("%d%d", &u, &v), add(u, v), add(v, u);
    	return;
    }
    void dfs(int u, int fa){
    	f[u] = inf; g[u] = 0;
    	for(int i = hd[u]; i; i = nxt[i]){
    		int v = to[i]; if(v == fa) continue;
    		dfs(v, u);
    		f[u] = min(f[u], f[v] + 1);
    		g[u] = max(g[u], g[v] + 1);
    	}
    	if(f[u] + g[u] <= mid) g[u] = -inf;
    	else if(g[u] == mid) f[u] = 0, g[u] = -inf, ret++;
    }
    bool check(){
    	ret = 0;
    	dfs(1, 0);
    	if(g[1] >= 0) ret++;
    	return ret <= k;
    }
    void solve(){
    	int l = 0, r = n, ans = n; 
    	while(l <= r){
    		mid = (l + r) >> 1;
    		if(check()) r = mid - 1, ans = mid;
    		else l = mid + 1;
    	}
    	printf("%d
    ", ans);
    }
    int main(){
    	init(); solve();
    	return 0;
    }
    

    F - Deque Game

    (k) 个序列,A 和 B 在博弈,A 先手,每次选择一个长度大于 1 的序列,丢掉头或者尾。

    A 希望终和最大,B 希望终和最小。

    考虑只有一个奇数长度的序列怎么做。

    • (len = 3) 枚举发现答案为 (min(a_2,max(a_1,a_3)))
    • 归纳法可得一个奇数长度序列答案为 (min(a_{mid},max(a_{mid-1}, a_{mid+1})))

    考虑偶数序列。

    奇数个偶数序列时,先操作偶数序列,奇数序列最大权值是 (max(a_{mid},min(a_{mid-1}, a_{mid+1}))) ,如果先手先操作奇数序列,后手直接在相反侧取,会导致答案为 (a_{mid}),不如先操作偶数序列可能更优。

    后手在中途跑去操作奇数序列先手也可以跟去。

    偶数个偶数序列时,

    如果先手先操作一个偶数序列,操作后就有奇数个偶数序列,后手要是先操作偶数序列,奇数序列给的最小权值是 (min(a_{mid},max(a_{mid-1}, a_{mid+1}))) ,但如果后手先操作奇数序列,先手就可以搞成异侧取,弄成 (a_{mid}) ,不会优于先操作偶数序列。

    如果先手先操作奇数序列,奇数序列答案不变,但偶数序列答案也不变,如果后手先去操作偶数序列,先手就凉了。(好像是这样吧,我晕了)

    const int N = 2e5 + 10;
    int n, q[N];
    vector<int> a[N];
    int main(){
    	scanf("%d", &n);
    	int cnt = 0;
    	for(int i = 1; i <= n; i++){
    		int k; scanf("%d", &k);
    		for(int j = 0, x; j < k; j++)
    			scanf("%d", &x), a[i].push_back(x);
    		cnt += (k & 1 ^ 1);
    	}
    	ll sum = 0; int len = 0;
    	for(int i = 1; i <= n; i++){
    		if(a[i].size() & 1 ^ 1) {
    			if(a[i].size() == 2){
    				sum += min(a[i][0], a[i][1]);
    				q[++len] = - (max(a[i][0], a[i][1]) - min(a[i][0], a[i][1]));
    			} else {
    				int mid0 = a[i].size() / 2 - 1, mid1 = a[i].size() / 2 + 1 - 1, ret0, ret1;
    				if(cnt & 1 ^ 1){
    					ret0 = min(a[i][mid0], max(a[i][mid0 - 1], a[i][mid0 + 1]));
    					ret1 = min(a[i][mid1], max(a[i][mid1 - 1], a[i][mid1 + 1]));
    				} else {
    					ret0 = max(a[i][mid0], min(a[i][mid0 - 1], a[i][mid0 + 1]));
    					ret1 = max(a[i][mid1], min(a[i][mid1 - 1], a[i][mid1 + 1]));
    				}
    				sum += min(ret0, ret1);
    				q[++len] = - (max(ret0, ret1) - min(ret0, ret1));
    			}
    		}
    	}
    	for(int i = 1; i <= n; i++){
    		if(a[i].size() & 1) {
    			if(a[i].size() == 1){
    				sum += a[i][0];
    			} else {
    				int mid0 = (a[i].size() + 1) / 2 - 1;
    				if(cnt & 1 ^ 1)
    					sum += min(a[i][mid0], max(a[i][mid0 - 1], a[i][mid0 + 1]));
    				else 
    					sum += max(a[i][mid0], min(a[i][mid0 - 1], a[i][mid0 + 1]));
    			}
    		}
    	}
    	sort(q + 1, q + len + 1);
    	for(int i = 1; i <= len; i += 2) sum -= q[i];
    	printf("%lld
    ", sum);
    	return 0;
    }
    
    
    
    qaqaq
  • 相关阅读:
    Linux 修改时区(debain)
    C#生成验证码
    httpPost 请求
    C# Array.FindAll
    C#删除字符串中所有的空字符
    C# 获取汉字区位码
    Qinq Vlan mapping 和DHCP 服务器
    Sql 分页存储过程
    request 之getParameterMap 方法
    如果我是面试官
  • 原文地址:https://www.cnblogs.com/zdsrs060330/p/14719544.html
Copyright © 2011-2022 走看看