Codeforces Round #539 (Div. 2)
Posted dup4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #539 (Div. 2)相关的知识,希望对你有一定的参考价值。
A. Sasha and His Trip
签。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 int n, v; 5 6 int main() 7 { 8 while (scanf("%d%d", &n, &v) != EOF) 9 { 10 int res = 0; 11 if (v >= n - 1) res = n - 1; 12 else 13 { 14 res = v; 15 for (int i = 1, j = 2; i <= n - 1 - v; ++i, ++j) 16 res += j; 17 } 18 printf("%d ", res); 19 } 20 return 0; 21 }
B. Sasha and Magnetic Machines
签。
如果可以换无限次怎么做?
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 50010 5 vector <int> fac[110]; 6 int n, a[N], cnt[110]; 7 8 int main() 9 { 10 for (int i = 2; i <= 100; ++i) 11 { 12 fac[i].clear(); 13 for (int j = 2; j <= i; ++j) if (i % j == 0) 14 fac[i].push_back(j); 15 } 16 while (scanf("%d", &n) != EOF) 17 { 18 int res = 0; 19 memset(cnt, 0, sizeof cnt); 20 for (int i = 1; i <= n; ++i) 21 { 22 scanf("%d", a + i); 23 res += a[i]; 24 ++cnt[a[i]]; 25 } 26 int tot = res; 27 for (int i = 1; i <= 100; ++i) 28 { 29 for (int j = 1; j <= 100; ++j) if (cnt[i] && cnt[j] && i != j) 30 { 31 int tmp = i + j; 32 for (auto it : fac[i]) 33 res = min(res, tot - tmp + i / it + j * it); 34 } 35 } 36 for (int i = 1; i <= 100; ++i) if (cnt[i] >= 2) 37 { 38 int tmp = 2 * i; 39 for (auto it : fac[i]) 40 res = min(res, tot - tmp + i * it + i / it); 41 } 42 printf("%d ", res); 43 } 44 return 0; 45 }
C. Sasha and a Bit of Relax
Solved.
题意:
有一个数列,找出多少个$(l, r) 使得 r - l + 1 是偶数 并且$
$a_l oplus a_{l + 1} oplus cdots oplus a_{mid} = a_{mid +1} oplus a_{mid +2} oplus cdots oplus a_r$
思路:
令$f[]表示前缀异或$
$那么第二个条件用前缀异或来表示就是 f_r oplus f_{mid} = f_{mid} oplus f_{l - 1}$
其实就是统计有多少个$f_r 和 f_{l - 1} 相同,并且 r - l +1 是偶数$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 300010 6 #define M 1100000 7 int n, a[N], sum[N]; 8 int cnt[M][2]; 9 10 ll f(int n) 11 { 12 return 1ll * n * (n - 1) / 2; 13 } 14 15 int main() 16 { 17 while (scanf("%d", &n) != EOF) 18 { 19 sum[0] = 0; 20 memset(cnt, 0, sizeof cnt); 21 ++cnt[0][0]; 22 for (int i = 1; i <= n; ++i) 23 { 24 scanf("%d", a + i); 25 sum[i] = sum[i - 1] ^ a[i]; 26 ++cnt[sum[i]][i & 1]; 27 } 28 ll res = 0; 29 for (int i = 0; i < (1 << 20); ++i) 30 { 31 res += f(cnt[i][0]) + f(cnt[i][1]); 32 } 33 printf("%lld ", res); 34 } 35 return 0; 36 }
D. Sasha and One More Name
Solved.
题意:
给出一个回文串,可以将该回文串切成若干段再任意拼接
使得拼接之后的串也是回文串并且不是原串
求最小的切割次数
思路:
首先可以考虑一次切割是否可行,可以$O(n^2)判断$
$再考虑二次切割,如果二次切割不行,那么次数再增加都不行$
$二次切割的情况,即将原串一分为二,在左边找一个子串使得这个子串不是回文串$
$那么把这个回文串倒置一下和右边对应位置交换即可$
$首先我们考虑起点都是原串的起点,只需要枚举子串的终点即可$
$因为如果存在某个子串它的起点不是初始起点使得它不是回文,那么将起点移到初始起点,它也不是回文$
$再考虑如果找不到,那么说明所有子串都是回文,这种情况就是所有字符都相等$
$当然如果原串长度是奇数,中间那个字符可以不用考虑$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 5010 5 char s[N]; 6 int len; 7 8 bool ok(string s) 9 { 10 int len = s.size(); 11 for (int i = 0; i < len / 2; ++i) 12 if (s[i] != s[len - i - 1]) 13 return false; 14 return true; 15 } 16 17 bool same(string str) 18 { 19 for (int i = 0; i < len; ++i) 20 if (str[i] != s[i + 1]) 21 return false; 22 return true; 23 } 24 25 int solve() 26 { 27 len = strlen(s + 1); 28 for (int i = 1; i < len; ++i) 29 { 30 string tmp = ""; 31 for (int j = i + 1; j <= len; ++j) tmp += s[j]; 32 for (int j = 1; j <= i; ++j) tmp += s[j]; 33 if (!same(tmp) && ok(tmp)) return 1; 34 } 35 for (int i = len; i > 1; --i) 36 { 37 string tmp = ""; 38 for (int j = i; j <= len; ++j) tmp += s[j]; 39 for (int j = 1; j < i; ++j) tmp += s[j]; 40 if (!same(tmp) && ok(tmp)) return 1; 41 } 42 string tmp = ""; 43 for (int i = 1; i <= len / 2; ++i) 44 { 45 tmp += s[i]; 46 if (!ok(tmp)) 47 return 2; 48 } 49 return -1; 50 } 51 52 53 int main() 54 { 55 while (scanf("%s", s + 1) != EOF) 56 { 57 int res = solve(); 58 if (res != -1) printf("%d ", res); 59 else puts("Impossible"); 60 } 61 return 0; 62 }
F. Sasha and Interesting Fact from Graph Theory
Upsolved.
题意:
要求构造一棵$n$个点的树,使得$a->b的距离为m$
$每条边的边权在[1, m]范围内$
$求生成树个数$
思路:
我们可以枚举$a->b的边数,那么边权的分配就有C_{m - 1}^{edge}$
$并且可以有顺序的选出edge - 1个点是A_{n}^{edge - 1}$
$那么再考虑其他点,剩下的点的个数为n - edge - 1$
$这个点的边的选择都是m种,就是m^{n - edge - 1}$
$再考虑他们构成一棵树,就是有n个点,要分配到k个不同的连通块构成的森林的方案$
$根据Cayley公式f(n, k) = k cdot n^{n - y - 1}$
$我们要的就是f(n, edge +1)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 1000010 6 const ll p = (ll)1e9 + 7; 7 int n, m, a, b; 8 ll fac[N], inv[N]; 9 10 ll qmod(ll base, ll n) 11 { 12 ll res = 1; 13 while (n) 14 { 15 if (n & 1) res = res * base % p; 16 base = base * base % p; 17 n >>= 1; 18 } 19 return res; 20 } 21 22 ll C(int n, int m) 23 { 24 if (m > n) return 0; 25 return fac[n] * inv[m] % p * inv[n - m] % p; 26 } 27 28 int main() 29 { 30 fac[0] = 1; 31 for (int i = 1; i <= 1000000; ++i) fac[i] = fac[i - 1] * i % p; 32 inv[1000000] = qmod(fac[1000000], p - 2); 33 for (int i = 1000000; i >= 1; --i) inv[i - 1] = inv[i] * i % p; 34 while (scanf("%d%d%d%d", &n, &m, &a, &b) != EOF) 35 { 36 ll base = 1; 37 ll res = 0; 38 for (int i = n - 2; i >= 0; --i) 39 { 40 base = 1ll * qmod(m, n - 2 - i); 41 if (n - i - 3 >= 0) 42 base = base * (i + 2) % p * qmod(n, n - i - 3) % p; 43 res = (res + C(m - 1, i) * C(n - 2, i) % p * base % p * fac[i] % p) % p; 44 //base = base * m % p * (i + 1) % p; 45 } 46 printf("%lld ", res); 47 } 48 return 0; 49 }
以上是关于Codeforces Round #539 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #539 (Div. 2)
Codeforces Round #539 (Div. 2) C Sasha and a Bit of Relax
Codeforces Round #436 E. Fire(背包dp+输出路径)
[ACM]Codeforces Round #534 (Div. 2)