zoukankan      html  css  js  c++  java
  • Codeforces Round #572 (Div. 2)

    Contest Info


    [Practice Link](https://codeforc.es/contest/1189)
    Solved A B C D1 D2 E F
    6/7 Ø Ø Ø Ø Ø Ø -
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    A. Keanu Reeves

    签到题。

    #include <bits/stdc++.h>
    using namespace std;
     
    #define N 1100
    char s[N]; int n;
     
    int main() {
    	while (scanf("%d%s", &n, s + 1) != EOF) {
    		int cnt = 0;
    		for (int i = 1; i <= n; ++i) {
    			if (s[i] == '1') ++cnt;
    			else --cnt;
    		}  
    		if (cnt) {
    			puts("1"); puts(s + 1);
    		} else {
    			puts("2");
    			printf("%c %s
    ", s[1], s + 2);
    		}
    	}
    	return 0;
    }
    

    B. Number Circle

    题意:
    有一个序列(a_1, a_2, cdots, a_n),要求重新排列构成一个环,任意一个数都要满足严格小于旁边两数之和。
    输出方案;

    思路:
    本来的想法是最大的放中间,次大,第三大的放旁边这样一次放下去,但是发现这样并不总能构造出解。
    后来想想,直接降序排,那么其中除了最大的一个元素可能不满足,其他元素肯定都满足。
    那么我们先降序排,有(a_n, a_{n - 1}, cdots, a_1)
    然后将(a_{n - 1})移到最后一个,依然满足其他元素都满足,最大的那个元素可能不满足。
    但是这个情况下,如果最大的元素都不满足,那肯定满足不了了,因为和最大的元素相邻的是次大的和第三大的。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
     
    #define N 100010
    int n, a[N], b[N];
     
    bool ok(int *a) {
    	if (a[2] + a[n] <= a[1]) return 0;
    	if (a[1] + a[n - 1] <= a[n]) return 0;
    	for (int i = 2; i < n; ++i) {
    		if (a[i - 1] + a[i + 1] <= a[i]) {
    			return 0;
    		}
    	}
    	return 1;
    }
     
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    		sort(a + 1, a + 1 + n, [](int x, int y) {
    			return x > y;		
    		});
    		b[1] = a[1];
    		for (int i = 3; i <= n; ++i) b[i - 1] = a[i];
    		b[n] = a[2];
    		if (ok(b)) {
    			puts("YES");
    			for (int i = 1; i <= n; ++i) printf("%d%c", b[i], " 
    "[i == n]);
    		} else {
    			puts("NO");
    		}
    	}
    	return 0;
    }
    

    C. Candies!

    题意:
    (n)个数(s_i(0 leq s_i leq 9)),定义这样一种过程:

    • 对于长度为(2)的幂次的子区间([a_1, a_2, cdots, a_{2^k}]),每次替换((a_{2i}, a_{2i + 1})(0 leq i < 2^{k -1}))((a_{2i} + a_{2i + 1}) mod 10)
    • 如果某一步的(a_{2i} + a_{2i + 1} >= 10),那么会获得一个糖果
    • 重复操作,知道序列中数的个数变为(1)
      每次询问(f[a_1, a_2, cdots, a_{2^k}])表示([a_1, a_2, cdots, a_{2^k}])这个区间执行上述操作最后得到的糖果个数是多少。

    思路:
    (f[i][j])表示以第(i)位为起点,长度为(j)的区间的糖果个数多少,倍增即可。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
     
    #define N 100010
    #define D 20
    int n, q, l, r, a[N];
    int f[N][20], g[N][20];
     
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		memset(f, 0, sizeof f);
    		memset(g, 0, sizeof g);
    		for (int i = 1; i <= n; ++i) scanf("%d", a + i), g[i][0] = a[i]; 
    		for (int j = 1; j <= 20; ++j) {
    			for (int i = 1; i <= n; ++i) {
    				if (i + (1 << j) - 1 > n) break;
    				int nx = (i + (1 << (j - 1)));
    				f[i][j] = f[i][j - 1] + f[nx][j - 1];
    				g[i][j] = g[i][j - 1] + g[nx][j - 1];
    				if (g[i][j] >= 10) {
    					++f[i][j];
    					g[i][j] %= 10;
    				}
    			}
    		}
    		scanf("%d", &q);
    		while (q--) {
    			scanf("%d%d", &l, &r);
    			int t = r - l + 1, q = 0;
    			while (t) {
    				++q;
    				t /= 2;
    			}
    			--q;
    			printf("%d
    ", f[l][q]);
    		}
    	}
    	return 0;
    }
    

    D1. Add on a Tree

    题意:
    有一棵树,每次可以选取两个叶子结点,将这两个叶子的简单路径上的所有边的边全加上(x)
    询问给定任意一种边权方案,是否都能通过有限次这种操作完成。

    思路:
    当且仅当树中没有度数为(2)的点的时候,可以。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
     
    #define N 100010
    int n, a[N], d[N];
     
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		memset(d, 0, sizeof d);
    		for (int i = 1, u, v; i < n; ++i) {
    			scanf("%d%d", &u, &v);
    			++d[u]; ++d[v];
    		}
    		bool F = 1;
    		for (int i = 1; i <= n; ++i) if (d[i] == 2) F = 0;
    		puts(F ? "YES" : "NO");
    	}
    	return 0;
    }
    

    D2. Add on a Tree: Revolution

    题意:
    和D1的不同之处在于每次加的(x)都是整数,而且这次给出边的需求边权,要求一种方案。并且边权都是偶数。

    思路:
    当且仅当树中没有度数为(2)的点的时候, 为什么?
    首先,除了叶子结点意外以外,其他结点的度数都(>= 3)。 那么我们考虑其中一个点(u),有三个点(l_1, l_2, v)分别属于(u)的三个不同子树。
    那么我们要想改变((u, v))这条边的边权为(x),那么我们这么操作:

    • ((g[v], g[l_1]))(frac{x}{2})
    • ((g[v], g[l_2]))(frac{x}{2})
    • ((g[l_1], g[l_2]))(-frac{x}{2})

    其中(g[u])表示的是(u)子树下的某个叶子结点。
    这样之后我们发现我们将((g[l_1], g[l_2]))上的边的边权恢复原状了。
    而只改动了((u, g[v]))路径上的边,并且((u, v))这条边已经达到要求了。
    ((v, g[v]))这些边直接更改他们的需求,递归下去做即可。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define N 1100
    int n, leaf[N], W[N], g[N], root;   
    int e[N][3];
    vector <vector<int>> G;
    struct node {
    	int u, v, w;
    	node() {}
    	node(int u, int v, int w) : u(u), v(v), w(w) {}
    };
    vector <node> res; 
    
    bool ok() {
    	for (int i = 1; i <= n; ++i) {
    		if (G[i].size() == 2) {
    			return 0;
    		}
    		if (root == -1 || G[i].size() > G[root].size()) {
    			root = i;
    		}
    	}	
    	return 1;
    }
    
    int getleaf(int u) {
    	if (G[u].size() == 0) return u;
    	for (auto v : G[u]) {
    		return getleaf(v); 
    	}
    }
    
    int fa[N];
    void pre(int u) {
    	for (auto v : G[u]) if (v != fa[u]) {
    		fa[v] = u;
    		pre(v);
    	}
    }
    
    void DFS(int u) {
    	if (G[u].empty()) return;
    	for (auto v : G[u]) leaf[v] = getleaf(v); 
    	int sze = (int)G[u].size();
    	if (sze >= 2) {
    		g[G[u][0]] = leaf[G[u][1]];  
    	}
    	for (int i = 1; i < sze; ++i) {
    		g[G[u][i]] = leaf[G[u][i - 1]];
    	}
    	for (int sze = (int)G[u].size(), i = 0; i < sze; ++i) {
    		int v = G[u][i];
    	    int nx, nnx;
    		if (u == root) {
    			if (i == 0) {
    				nx = leaf[G[u][1]], nnx = leaf[G[u][2]];
    			} else if (i == sze - 1) {
    				nx = leaf[G[u][i - 1]], nnx = leaf[G[u][i - 2]];	
    			} else {
    				nx = leaf[G[u][i - 1]], nnx = leaf[G[u][i + 1]];
    			}
    		} else {
    			nx = g[u];
    			if (i == 0) {
    				nnx = leaf[G[u][1]];
    			} else {
    				nnx = leaf[G[u][i - 1]];
    			}
    		}	
    		res.push_back(node(leaf[v], nx, W[v] / 2));
    		res.push_back(node(leaf[v], nnx, W[v] / 2));
    		res.push_back(node(nx, nnx, -W[v] / 2));
    		//cout << v << " " << nx << " " << nnx << endl;
    		int it = leaf[v];
    		while (it != v) {
    			W[it] -= W[v];
    			it = fa[it];
    		}
    	}
    	for (auto v : G[u]) DFS(v);
    }
    	
    int main() {
    	while (scanf("%d", &n) != EOF) {
    		G.clear(); G.resize(n + 1); 
    		for (int i = 1; i < n; ++i) {
    			int &u = e[i][0], &v = e[i][1], &w = e[i][2];
    			scanf("%d%d%d", &u, &v, &w);
    			G[u].push_back(v);
    			G[v].push_back(u);
    		}
    		root = -1;
    		if (!ok()) {
    			puts("NO");
    		} else {
    			if (n == 2) {
    				printf("YES
    1
    ");
    				printf("1 2 %d
    ", e[1][2]);
    				continue;
    			}
    			res.clear();
    			pre(root);
    			G.clear(); G.resize(n + 1);
    			for (int i = 1; i < n; ++i) {
    				if (fa[e[i][0]] == e[i][1]) {
    					swap(e[i][0], e[i][1]);
    				}
    				G[e[i][0]].push_back(e[i][1]);
    				W[e[i][1]] = e[i][2];
    			}
    			DFS(root); 
    			puts("YES");
    			printf("%d
    ", (int)res.size());
    			assert(res.size() <= 100000);
    			for (auto it : res) {
    				printf("%d %d %d
    ", it.u, it.v, it.w);
    			}
    		}
    	}
    	return 0;
    }
    

    E. Count Pairs

    题意:
    给出(n)个数(a_i),询问有多少对((i, j))满足((a_i + a_j)(a_i^2 + a_j^2) equiv k mod p)

    思路:

    [egin{eqnarray*} (a_i + a_j)(a_i^2 + a_j^2) &equiv& k mod p ightarrow \ (a_i + a_j)(a_i - a_j)(a_i^2 + a_j^2) &equiv& k(a_i - a_j) mod p ightarrow \ (a_i^4 - a_j^4) &equiv& k(a_i - a_j) mod p ightarrow \ (a_i^4 - ka_i) - (a_j^4 - ka_j) &equiv& 0 mod p ightarrow \ a_i^4 - ka_i &equiv& a_j^4 - ka_j mod p end{eqnarray*} ]

    然后直接统计即可。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
     
    #define N 300010
    #define ll long long
    int n; ll p, k, a[N];
    map <ll, int> mp;
     
    int main() {
    	while (scanf("%d%lld%lld", &n, &p, &k) != EOF) {
    		for (int i = 1; i <= n; ++i) {
    			scanf("%lld", a + i);
    			a[i] = (a[i] * a[i] % p * a[i] % p - k + p) % p * a[i] % p;
    		}
    		sort(a + 1, a + 1 + n);
    		mp.clear();
    		ll res = 0;
    		for (int i = 1; i <= n; ++i) {
    			if (mp.find(a[i]) != mp.end()) {
    				res += mp[a[i]]; 
    			}
    		//	if (mp.find(p - a[i]) != mp.end()) {
    		//		res += mp[p - a[i]];
    		//	}
    			mp[a[i]]++;
    		}
    		printf("%lld
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Codeforces Round #281 (Div. 2) A. Vasya and Football(模拟)
    自动生成代码工具
    导入导出维护计划
    收集错误日志方法
    C#常用控件和属性
    人民币转换
    身份证验证
    设置下拉列表项的默认值
    清除维护任务
    清除MSSQL历史记录
  • 原文地址:https://www.cnblogs.com/Dup4/p/11144057.html
Copyright © 2011-2022 走看看