Contests 链接:Codeforces Round #482 (Div. 2)
过题数:2
排名:843/10089
A. Pizza, Pizza, Pizza!!!
题意
用最少的线将一个圆平分成 n+1 n + 1 块。
输入
输入只包含一个整数 n (0≤n≤1018) n ( 0 ≤ n ≤ 10 18 ) 。
输出
输出需要的线的数量。
样例
输入 |
---|
3 |
输出 |
2 |
输入 |
---|
4 |
输出 |
5 |
题解
如果 n n 为奇数,就要平分成偶数块,就需要 条线,如果 n n 为偶数,就需要平分成奇数块,每条线必须从圆心往外,需要 条线,注意 n n 为 就不需要线。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
using namespace std;
#define LL long long
LL int n;
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("10.out", "w", stdout);
#endif // LOCAL
while(scanf("%I64d", &n) != EOF) {
if(n == 0) {
printf("0\n");
continue;
}
++n;
if(n % 2 == 0) {
printf("%I64d\n", n / 2);
} else {
printf("%I64d\n", n);
}
}
return 0;
}
B. Treasure Hunt
题意
Kuro K u r o 、 Shiro S h i r o 和 Katie K a t i e 三人都有一个长度相同的字符串,每个字符串都只包含小写字母和大写字母,三个人都有 n n 次对自己的字符串进行操作的机会,每次操作可以选择一个字符并将这个字符修改成另一个字符。一个字符串的价值定义为这个字符串中所有子串出现的最大次数,他们三人经过 轮操作后,在采取最优策略下,谁的字符串价值将会最大。
输入
第一行为一个整数 n (0≤n≤109) n ( 0 ≤ n ≤ 10 9 ) ,接下去三行为三个字符串,分别为 Kuro,Shiro K u r o , S h i r o 和 Katie K a t i e 的初始字符串,字符串的长度不超过 105 10 5 ,字符串只包含小写字母和大写字母。
输出
输出三人都采取最优策略下,字符串价值最大的人,如果存在两个或两个以上最大价值,输出 Draw D r a w 。
样例
输入 |
---|
3Kuroo Shiro Katie |
输出 |
Kuro |
提示 |
3
3
轮之后, 可以将自己的字符串修改为 ooooo ,价值为
5
5
,而另外两个人最多只能得到价值为 的字符串。 |
输入 |
---|
7treasurehunt threefriends hiCodeforces |
输出 |
Shiro |
输入 |
---|
1abcabc cbabac ababca |
输出 |
Katie |
输入 |
---|
15foPaErcvJ mZaxowpbt mkuOlaHRE |
输出 |
Draw |
提示 |
每个人都可以将自己的字符串修改成 9 9 个相同的字符,因此三人平局。 |
题解
如果某个长度大于 的子串是字符串中出现次数最多的子串,那么这个子串中的字符一定也是出现最多的子串,因此只要处理所有字符即可,对于每个人都计算出可能的最大价值再进行比较就能知道赢家。如果某个字符串的字符完全相等且 n n 等于 ,那么这个符串的价值只能等于 |s|−1 | s | − 1 ,如果 Max+n≤|s| M a x + n ≤ | s | (其中 Max M a x 为字符出现的最大次数),那么最大价值就是 Max+n M a x + n ,否则字符串的价值就可以达到 |s| | s | 。
过题代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <climits> #include <cstring> #include <string> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> #include <algorithm> using namespace std; #define LL long long const int maxn = 100000 + 100; int n; char str[3][maxn]; int score[3]; map<char, int> mp[3]; int len[3]; map<int, int> mpp; map<int, int>::iterator it; int getscore(int Index, char ch) { int tmp = n - (len[Index] - mp[Index][ch]); if(tmp >= 0) { if(mp[Index][ch] == len[Index] && tmp == 1) { return len[Index] - 1; } return len[Index]; } return n + mp[Index][ch]; } int main() { #ifdef LOCAL freopen("test.txt", "r", stdin); // freopen("10.out", "w", stdout); #endif // LOCAL while(scanf("%d", &n) != EOF) { mpp.clear(); memset(score, 0, sizeof(score)); for(int i = 0; i < 3; ++i) { mp[i].clear(); scanf("%s", str[i]); len[i] = strlen(str[i]); for(int j = 0; str[i][j]; ++j) { ++mp[i][str[i][j]]; } } for(char ch = 'a'; ch <= 'z'; ++ch) { for(int i = 0; i < 3; ++i) { score[i] = max(score[i], getscore(i, ch)); } } for(char ch = 'A'; ch <= 'Z'; ++ch) { for(int i = 0; i < 3; ++i) { score[i] = max(score[i], getscore(i, ch)); } } int Max = 0; for(int i = 0; i < 3; ++i) { Max = max(Max, score[i]); ++mpp[score[i]]; } int cnt = 0; int ans = 0; for(int i = 0; i < 3; ++i) { if(score[i] == Max) { ++cnt; ans = i; } } if(cnt >= 2) { printf("Draw\n"); } else { switch(ans) { case 0: printf("Kuro\n"); break; case 1: printf("Shiro\n"); break; case 2: printf("Katie\n"); break; } } } return 0; }
C. Kuro and Walking Route
题意
在一棵 n n 个节点的树上, 表示从节点 u u 到节点 的一条路径,其中 (u,v) ( u , v ) 与 (v,u) ( v , u ) 被认为是不同的路径,问有多少条路径不会先经过节点 x x 再经过节点 。
输入
第一行包含三个整数 n,x,y (1≤n≤3×105,1≤x,y≤n,x≠y) n , x , y ( 1 ≤ n ≤ 3 × 10 5 , 1 ≤ x , y ≤ n , x ≠ y ) ,接下去 n−1 n − 1 行每行两个整数 a,b (1≤a,b≤n,a≠b) a , b ( 1 ≤ a , b ≤ n , a ≠ b ) ,表示节点 a a 和节点 之间有一条边,数据保证给出的边集能构成一棵树。
输出
输出合法的路径数量。
样例
输入 3 1 3
1 2
2 3输出 5
输入 3 1 3
1 2
1 3输出 4 题解
将所有路径数 A2n A n 2 减去不合法的路径数就是答案,不合法路径就是先经过 x x 再经过 的路径,先以 x x 为根 统计 y y 的子树节点数 ,再以 y y 为根 统计 x x 的子树节点数量 ,不合法路径数就是 sonx×sony s o n x × s o n y 。
过题代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <climits> #include <cstring> #include <string> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> #include <algorithm> using namespace std; #define LL long long const int maxn = 300000 + 100; LL n; int x, y, u, v; vector<int> G[maxn]; int sum[maxn]; void dfs(int f, int x) { sum[x] = 1; int len = G[x].size(); for(int i = 0; i < len; ++i) { int pos = G[x][i]; if(pos != f) { dfs(x, pos); sum[x] += sum[pos]; } } } int main() { #ifdef LOCAL freopen("test.txt", "r", stdin); // freopen("10.out", "w", stdout); #endif // LOCAL while(scanf("%I64d%d%d", &n, &x, &y) != EOF) { for(int i = 1; i <= n; ++i) { G[i].clear(); } for(int i = 1; i < n; ++i) { scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } dfs(x, x); LL ans = sum[y]; dfs(y, y); ans *= sum[x]; printf("%I64d\n", n * (n - 1) - ans); } return 0; }
D. Kuro and GCD and XOR and SUM
题意
初始有一个空的集合,有 q q 次操作,每次操作有两种选择:
- 给定 ,表示将 ui u i 加入到集合中;
- 给定 xi,ki,si x i , k i , s i ,从集合中找到一个整数 v v ,要求 满足条件 ki|gcd(xi,v),xi+v≤si k i | gcd ( x i , v ) , x i + v ≤ s i 且 xi⊕v x i ⊕ v 的值最大。
输入
第一行为一个整数 q (2≤q≤105) q ( 2 ≤ q ≤ 10 5 ) ,接下去 q q 行,每行可以是以下两种格式:
- 第一个数字为 ,后面跟着一个整数 ui (1≤ui≤105) u i ( 1 ≤ u i ≤ 10 5 ) ,表示第一种操作;
- 第一个数字为 2 2 ,后面跟着三个整数 ,表示操作 2 2 。
输出
对于每次操作 ,如果可以找到合法的 v v ,则输出 的值,否则输出 −1 − 1 。
样例
输入 5
1 1
1 2
2 1 1 3
2 1 1 2
2 1 1 1输出 2
1
-1提示 1.向集合中加入数字 1 1 ,则集合为 ;
2.向集合中加入数字 2 2 ,则集合为 ;
3. 1|gcd(1,1),1+1≤2,1⊕1=0;1|gcd(1,2),1+2≤3,1⊕2=3 1 | gcd ( 1 , 1 ) , 1 + 1 ≤ 2 , 1 ⊕ 1 = 0 ; 1 | gcd ( 1 , 2 ) , 1 + 2 ≤ 3 , 1 ⊕ 2 = 3 因此答案为 2 2 ;
4.只有 满足前两个条件,因此答案为 1 1 ;
5.无法找到满足条件的数字,因此答案为 。
输入 10
1 9
2 9 9 22
2 3 3 18
1 25
2 9 9 20
2 25 25 14
1 20
2 26 26 3
1 14
2 20 20 9输出 9
9
9
-1
-1
-1题解
若 ki k i 不能整除 xi x i ,直接输出 −1 − 1 ,如果可以整除,答案就在 ki k i 的所有倍数中查找,建立 105 10 5 棵字典树,第 i i 棵字典树存的是集合中 的所有倍数,这样每加入一个数字 ui u i ,就将 ui u i 加入到他的所有约数的字典树中,对于每次 2 2 操作,直接在第 棵字典树上查找满足条件的答案即可,需要 O(nlnn) O ( n ln n ) 地预处理所有约数。
过题代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <cmath> #include <string> #include <vector> #include <list> #include <queue> #include <stack> #include <map> #include <set> #include <functional> #include <algorithm> using namespace std; #define LL long long const int maxn = 100000 + 100; vector<vector<int> > tree; vector<int> Min; int cnt; bool vis[maxn]; struct Trie { int root; int creat(int x) { int ret = cnt; ++cnt; tree.push_back(vector<int>(2, -1)); Min.push_back(x); return ret; } void Init() { root = creat(1000000000); } int id(int x, int Index) { return ((x >> (20 - Index)) & 1); } void add(int x) { int pos = root; Min[pos] = min(Min[pos], x); for(int i = 0; i <= 20; ++i) { int w = id(x, i); if(tree[pos][w] == -1) { tree[pos][w] = creat(x); } pos = tree[pos][w]; Min[pos] = min(Min[pos], x); } } int query(int x, int s) { int ret = 0; int num = 0; int pos = root; for(int i = 0; i <= 20; ++i) { int w = !id(x, i); if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) { w = !w; } else { ret |= (1 << (20 - i)); } if(tree[pos][w] == -1 || Min[tree[pos][w]] > s) { return -1; } num |= (w << (20 - i)); pos = tree[pos][w]; } return num; } }; int q, command, x, k, s; Trie t[maxn]; vector<int> fac[maxn]; int main() { #ifdef LOCAL freopen("test.txt", "r", stdin); // freopen("10.out", "w", stdout); #endif // LOCAL for(int i = 1; i < maxn; ++i) { t[i].Init(); for(int j = i; j < maxn; j += i) { fac[j].push_back(i); } } scanf("%d", &q); for(int i = 0; i < q; ++i) { scanf("%d", &command); if(command == 1) { scanf("%d", &x); if(vis[x]) { continue; } vis[x] = true; int len = fac[x].size(); for(int j = 0; j < len; ++j) { int num = fac[x][j]; t[num].add(x); } } else { scanf("%d%d%d", &x, &k, &s); if(x % k != 0 || s <= x) { printf("-1\n"); } else { printf("%d\n", t[k].query(x, s - x)); } } } return 0; }