A. Superhero Transformation
签
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 char s[N], t[N], Hash[N]; 6 7 bool ok() 8 { 9 int n = strlen(s + 1); 10 for (int i = 1; i <= n; ++i) 11 if (Hash[s[i]] != Hash[t[i]]) 12 return false; 13 return true; 14 } 15 16 int main() 17 { 18 memset(Hash, 0, sizeof Hash); 19 Hash['a'] = 1; 20 Hash['e'] = 1; 21 Hash['i'] = 1; 22 Hash['o'] = 1; 23 Hash['u'] = 1; 24 while (scanf("%s%s", s + 1, t + 1) != EOF) 25 { 26 int len1 = strlen(s + 1), len2 = strlen(t + 1); 27 if (len1 != len2) puts("No"); 28 else 29 puts(ok() ? "Yes" : "No"); 30 } 31 return 0; 32 }
B. Average Superhero Gang Power
Hacked.
注意如果最大值不止一个,那么去掉几个是不一定的
枚举即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 int n, k, m; 7 ll a[N]; 8 9 int main() 10 { 11 while (scanf("%d%d%d", &n, &k, &m) != EOF) 12 { 13 for (int i = 1; i <= n; ++i) scanf("%lld", a + i); 14 sort(a + 1, a + 1 + n); 15 for (int i = 1; i <= n; ++i) a[i] += a[i - 1]; 16 double res = a[n] * 1.0 / n; 17 for (int i = 0; i < n; ++i) 18 { 19 if (m < i) break; 20 ll add = min(1ll * (m - i), 1ll * k * (n - i)); 21 res = max(res, (a[n] - a[i] + add) * 1.0 / (n - i)); 22 } 23 printf("%.10f ", res); 24 } 25 return 0; 26 }
C. Creative Snap
递归求解即可,注意一整段空直接返回$A$
这样最多只有$k个长度为1的节点被访问到$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 6 int n, k, A, B; 7 vector <int> v; 8 9 ll CDQ(ll l, ll r) 10 { 11 if (r < l) return 0; 12 int num = upper_bound(v.begin(), v.end(), r) - lower_bound(v.begin(), v.end(), l); 13 if (num == 0) return A; 14 ll tmp = 1ll * (r - l + 1) * B * num; 15 if (l == r) return tmp; 16 ll mid = (l + r) >> 1; 17 return min(tmp, CDQ(l, mid) + CDQ(mid + 1, r)); 18 } 19 20 int main() 21 { 22 while (scanf("%d%d%d%d", &n, &k, &A, &B) != EOF) 23 { 24 v.clear(); 25 for (int i = 1, x; i <= k; ++i) 26 { 27 scanf("%d", &x); 28 v.push_back(x); 29 } 30 sort(v.begin(), v.end()); 31 printf("%lld ", CDQ(1, 1 << n)); 32 } 33 return 0; 34 }
D. Destroy the Colony
Solved.
题意:
有$n个人,n为偶数, 每个人有一个种类$
$询问给出x, y 要求将和第x人同种类并且和第y个人同种类的人放在一个集合$
$并且挑选出一些人和他们放在一起,剩下的人在另一个集合$
$要求两个集合人数相等,并且同一种类的人属于同个集合$
$给出有多少种分配方式, 集合里是有顺序的,并且两个集合是不同的$
思路:
考虑一共有$f种方式将其他人和第x人同种类的人以及第y人同种类的人放在一个集合$
$我们假定 第i种类的人有c_i个, 令m = frac{n}{2}$
$那么答案就是 frac {m! cdot m! cdot f cdot 2}{c_1! cdot c_2! cdots}$
那么考虑怎么处理$f, 可以用背包,但是暴力预处理时间复杂度是O(52^{3} cdot n)$
$但是我们可以先处理好总的,注意到对于每种情况的处理只有最多两项物品的删除$
$直接删除方案数即可 这样时间复杂度就是O(52^{2} cdot n)$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 const ll MOD = (ll)1e9 + 7; 7 char s[N]; 8 int cnt[110], Hash[210]; 9 int n, q, x, y, mid; 10 ll fac[N], inv[N]; 11 ll f[110][110]; 12 ll g[N]; 13 14 ll qmod(ll base, ll n) 15 { 16 ll res = 1; 17 while (n) 18 { 19 if (n & 1) res = res * base % MOD; 20 base = base * base % MOD; 21 n >>= 1; 22 } 23 return res; 24 } 25 26 ll C(int n, int m) 27 { 28 return fac[n] * inv[m] % MOD * inv[n - m] % MOD; 29 } 30 31 int main() 32 { 33 fac[0] = 1; 34 for (int i = 1; i <= 100000; ++i) fac[i] = (fac[i - 1] * i) % MOD; 35 inv[100000] = qmod(fac[100000], MOD - 2); 36 for (int i = 100000; i >= 1; --i) inv[i - 1] = (inv[i] * i) % MOD; 37 for (int i = 1; i <= 26; ++i) Hash['a' + i - 1] = i; 38 for (int i = 27; i <= 52; ++i) Hash['A' + i - 27] = i; 39 while (scanf("%s", s + 1) != EOF) 40 { 41 n = strlen(s + 1); 42 mid = n / 2; 43 memset(cnt, 0, sizeof cnt); 44 for (int i = 1; i <= n; ++i) ++cnt[Hash[s[i]]]; 45 ll tmp = 1; 46 for (int i = 1; i <= 52; ++i) 47 if (cnt[i]) tmp = (tmp * inv[cnt[i]]) % MOD; 48 memset(f, 0, sizeof f); 49 memset(g, 0, sizeof g); 50 g[0] = 1; 51 for (int i = 1; i <= 52; ++i) if (cnt[i]) 52 { 53 for (int j = mid; j >= cnt[i]; --j) 54 g[j] += g[j - cnt[i]]; 55 } 56 for (int i = 1; i <= 52; ++i) 57 { 58 for (int j = i + 1; j <= 52; ++j) 59 { 60 if (cnt[i] == 0 || cnt[j] == 0) continue; 61 if (cnt[i] + cnt[j] > mid) continue; 62 if (cnt[i] + cnt[j] == mid) 63 { 64 f[i][j] = f[j][i] = 1; 65 continue; 66 } 67 for (int k = cnt[i]; k <= mid; ++k) 68 g[k] -= g[k - cnt[i]]; 69 for (int k = cnt[j]; k <= mid; ++k) 70 g[k] -= g[k - cnt[j]]; 71 f[i][j] = f[j][i] = g[mid - cnt[i] - cnt[j]] % MOD; 72 //printf("%d %d %lld ", i, j, f[i][j]); 73 for (int k = mid; k >= cnt[i]; --k) 74 g[k] += g[k - cnt[i]]; 75 for (int k = mid; k >= cnt[j]; --k) 76 g[k] += g[k - cnt[j]]; 77 } 78 } 79 for (int i = 1; i <= 52; ++i) if (cnt[i] && cnt[i] <= mid) 80 { 81 for (int j = cnt[i]; j <= mid; ++j) 82 g[j] -= g[j - cnt[i]]; 83 f[i][i] = g[mid - cnt[i]] % MOD; 84 //printf("%d %lld ", i, f[i][i]); 85 //printf("%d %d %lld ", i, i, f[i][i]); 86 for (int j = mid; j >= cnt[i]; --j) 87 g[j] += g[j - cnt[i]]; 88 } 89 //for (int i = 1; i <= mid; ++i) printf("%lld%c", g[i], " "[i == mid]); 90 scanf("%d", &q); 91 while (q--) 92 { 93 scanf("%d%d", &x, &y); 94 //cout << f[Hash[s[x]]][Hash[s[y]]] << endl; 95 ll res = fac[mid] * fac[mid] % MOD * 2 % MOD * tmp % MOD * f[Hash[s[x]]][Hash[s[y]]] % MOD; 96 printf("%lld ", res); 97 } 98 } 99 return 0; 100 }
E. Tree
Upsolved.
题意:
在一棵树上
$每次询问给出一些点,根节点r以及组数m$
$要求将所有点分配到一个组中,最多分成m组,要求同一组的点任意两点不能是祖先关系$
$给出分配方案数$
思路:
考虑假如根节点是$1$
$dp[i][j] 表示到第i个点放进j个集合的方案数$
$首先要将点按DFS序排序 令f[i] 表示 i这个点有多少祖先在这里$
$dp[i][j] = dp[i - 1][j] * (j - f[i]) + dp[i - 1][j - 1]$
那么我们再考虑根节点任意的情况
$其实原来多少祖先就是点到1的路径上有多少点出现过$
$那么根节点任意的话 就是当前点到根节点的简单路径有多少点出现过$
$按照这个排序,就可以不重不漏的统计$
$维护节点出现个数 可以用DFS序+BIT 维护$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 const ll MOD = (ll)1e9 + 7; 7 int n, q; 8 vector <int> G[N]; 9 int f[N], vec[N], mark[N]; 10 ll dp[1010]; 11 12 int top[N], fa[N], deep[N], sze[N], son[N], lp[N], rp[N], cnt; 13 void DFS(int u) 14 { 15 sze[u] = 1; 16 for (auto v : G[u]) if (v != fa[u]) 17 { 18 fa[v] = u; 19 deep[v] = deep[u] + 1; 20 DFS(v); 21 sze[u] += sze[v]; 22 if (!son[u] || sze[v] > sze[son[u]]) son[u] = v; 23 } 24 } 25 26 void gettop(int u, int sp) 27 { 28 top[u] = sp; 29 lp[u] = ++cnt; 30 if (!son[u]) 31 { 32 rp[u] = cnt; 33 return; 34 } 35 gettop(son[u], sp); 36 for (auto v : G[u]) if (v != fa[u] && v != son[u]) 37 gettop(v, v); 38 rp[u] = cnt; 39 } 40 41 int lca(int u, int v) 42 { 43 while (top[u] != top[v]) 44 { 45 if (deep[top[u]] < deep[top[v]]) swap(u, v); 46 u = fa[top[u]]; 47 } 48 if (deep[u] > deep[v]) swap(u, v); 49 return u; 50 } 51 52 namespace BIT 53 { 54 int a[N]; 55 void init() { memset(a, 0, sizeof a); } 56 void update(int x, int val) 57 { 58 for (; x < N; x += x & -x) 59 a[x] += val; 60 } 61 int query(int x) 62 { 63 int res = 0; 64 for (; x > 0; x -= x & -x) 65 res += a[x]; 66 return res; 67 } 68 void update(int l, int r, int val) 69 { 70 update(l, val); 71 update(r + 1, -val); 72 } 73 }; 74 75 int main() 76 { 77 while (scanf("%d%d", &n, &q) != EOF) 78 { 79 for (int i = 1; i <= n; ++i) G[i].clear(); 80 memset(mark, 0, sizeof mark); 81 memset(son, 0, sizeof son); 82 cnt = 0; 83 BIT::init(); 84 for (int i = 1, u, v; i < n; ++i) 85 { 86 scanf("%d%d", &u, &v); 87 G[u].push_back(v); 88 G[v].push_back(u); 89 } 90 DFS(1); gettop(1, 1); 91 int k, m, r; 92 while (q--) 93 { 94 scanf("%d%d%d", &k, &m, &r); 95 for (int i = 0; i <= m; ++i) dp[i] = 0; dp[0] = 1; 96 for (int i = 1; i <= k; ++i) 97 scanf("%d", vec + i); 98 for (int i = 1; i <= k; ++i) 99 { 100 int x = vec[i]; 101 mark[x] = 1; 102 BIT::update(lp[x], rp[x], 1); 103 } 104 int ans_root = BIT::query(lp[r]); 105 for (int i = 1; i <= k; ++i) 106 { 107 int x = vec[i]; 108 int y = lca(x, r); 109 f[x] = BIT::query(lp[x]) + ans_root - 2 * BIT::query(lp[y]) + (mark[y] == 1) - 1; 110 } 111 for (int i = 1; i <= k; ++i) 112 { 113 int x = vec[i]; 114 mark[x] = 0; 115 BIT::update(lp[x], rp[x], -1); 116 } 117 sort(vec + 1, vec + 1 + k, [](int x, int y) 118 { 119 return f[x] < f[y]; 120 }); 121 if (f[vec[k]] >= m) puts("0"); 122 else 123 { 124 for (int i = 1; i <= k; ++i) 125 { 126 int x = vec[i]; 127 for (int j = min(i, m); j >= 0; --j) 128 { 129 if (j <= f[x]) dp[j] = 0; 130 else 131 dp[j] = (1ll * dp[j] * (j - f[x]) % MOD + dp[j - 1]) % MOD; 132 } 133 } 134 ll ans = 0; 135 for (int i = 1; i <= m; ++i) ans = (ans + dp[i]) % MOD; 136 printf("%lld ", ans); 137 } 138 } 139 } 140 return 0; 141 }