水题大赛

A. Superhero Transformation

1S 256MB

题意

给出两个小写字母串

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写

,询问是否可以把

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_02

串通过变化转成

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_03

串。字符串长度最大为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_04


变化次数不限:

  • 元音字母之间可以互相转换,如
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_05

  • ,但是
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_06

  • 辅音字母之间可以互相转换。如
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_07

  • ,但是
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_08

分析

判断长度是否相等,在判断每个位置上的数是否同为元音或者辅音。

CODE
#include <bits/stdc++.h>
using namespace std;
char a[1005], b[1005];
int n, m;
inline bool chk(char c) {
return c == 'a' || c == 'e' || c == 'i' || c == 'u' || c == 'o';
}
int main () {
scanf("%s%s", a+1, b+1);
n = strlen(a+1);
m = strlen(b+1);
if(n != m) return puts("No"), 0;
for(int i = 1; i <= n; ++i)
if(chk(a[i])^chk(b[i])) return puts("No"), 0;
puts("Yes");
}

B. Average Superhero Gang Power

1S 256MB

题意


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_09

个正整数

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_10


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_11

次操作。每次操作可以选择两种方式:

  • 一:给某个数加上
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_12

  • 二:删去某个数

要让平均值最大。有一个限制,作用在一个位置上的操作次数不超过

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_13


分析

按照贪心的策略,要删肯定从最小的开始删。那么排序后枚举删了几个数

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_14

,把剩下的操作数加在剩下

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_15

个位置上就行了,

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_16

的限制就取一个

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_17

就行了。

CODE

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n, k, m;
double a[MAXN];
int main () {
scanf("%d%d%d", &n, &k, &m);
for(int i = 1; i <= n; ++i)
scanf("%lf", &a[i]);
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i) a[i] += a[i-1];
double ans = a[n] / n;
for(int i = 0; i < n && i <= m; ++i) {
double add = min(1.0*m-i, 1.0*k*(n-i));
ans = max(ans, (a[n]-a[i]+add)/(n-i));
}
printf("%.10f\n", ans);
}

C. Creative Snap

1S 256MB

题意

你有一个长度为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_18

的序列,有

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_19

个位置上有人,题目给出。不同的人可能在相同的位置。你要控制整个序列,控制一个序列有两种方式:

  • 一:如果这个区间里面没有人,可以花费
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_20

  • 代价控制它;否则如果这个区间有
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_21

  • 个人,区间长度为
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_22

  • ,可以花费
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_23

  • 控制它。(
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_24

  • 题目给出
  • CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_25

  • 二:分别控制左半区间和右半区间。

要让控制整个序列的代价最小

分析

按题意递归即可,单位长度区间最多被访问

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_16

次,深度为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_27

,再加上里面有个,总时间复杂度即为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_28

(不满)

CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
int n, k, a[MAXN], A, B;
LL solve(int l, int r, int x, int y) {
if(x > y) return A;
LL now = 1ll * B * (y-x+1) * (r-l+1);
if(l == r) return now;
int mid = (l + r) >> 1;
int pos = upper_bound(a + x, a + y + 1, mid) - a;
return min(now, solve(l, mid, x, pos-1) + solve(mid+1, r, pos, y));
}
int main () {
scanf("%d%d%d%d", &n, &k, &A, &B);
for(int i = 1; i <= k; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + k + 1);
printf("%I64d\n", solve(1, 1<<n, 1, k));
}

D. Destroy the Colony

2S 512MB

题意

一个字符串

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_29

为偶数

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_30

由大小写字母组成,你可以将它重新排列,一个合法的排列方案必须满足相同字符(区分大小写)全部都在左半边

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_31

或者右半边

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_32

,即同一侧。


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_33

次询问,每次询问

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_34

,表示两个位置,记这两个位置上的字符分别为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_35


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_36

可能等于

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_37

)。你需要输出 满足所有的

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_20

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_39

字符都在同一侧
合法排序数

举个栗子,

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_40

。如果

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_41

,那么所有的

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_42

都要在同一侧,并且需要所有的

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_43

在同一侧。合法的方案就有

“aacbbb”,“bbbcaa”

“acabbb”,“bbbaca”

“caabbb”,“bbbaac”

分析

以下分析转自 Inspector_Javert的博客

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_44


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_45


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_46


由于每次只用

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_47


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_48

的值,再加上是无序字符对,

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_49

只用算一次。那么实际上复杂度为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_50

。而且因为只要

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_35

的出现次数加起来超过

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_48

就直接输出

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_53

,记忆化的话不一定把每个无序数对都做

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_47

,于是就能过了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int mod = 1e9 + 7;
char s[MAXN];
int n, m, c = 52, a[MAXN], cnt[55];
inline int num(char x) {
return (x >= 'a' && x <= 'z') ? x-'a'+1 : x-'A'+27;
}
int fac[MAXN>>1], inv[MAXN>>1];
inline void pre(int N) {
fac[0] = inv[0] = fac[1] = inv[1] = 1;
for(int i = 2; i <= N; ++i)
fac[i] = 1ll * fac[i-1] * i % mod,
inv[i] = 1ll * (mod - mod/i) * inv[mod%i] % mod;
for(int i = 2; i <= N; ++i)
inv[i] = 1ll * inv[i] * inv[i-1] % mod;
}
int ans[55][55], f[MAXN>>1], g[MAXN>>1], h[MAXN>>1];
int main () {
scanf("%s%d", s+1, &m);
n = strlen(s+1); pre(n/2);
for(int i = 1; i <= n; ++i)
++cnt[a[i] = num(s[i])];

int base = 1ll * fac[n/2] * fac[n/2] % mod;
for(int i = 1; i <= 52; ++i) if(cnt[i])
base = 1ll * base * inv[cnt[i]] % mod;

f[0] = 1;
for(int i = 1; i <= 52; ++i) if(cnt[i])
for(int j = n/2; j >= cnt[i]; --j)
f[j] = (f[j] + f[j-cnt[i]]) % mod;

memset(ans, -1, sizeof ans);
int x, y;
while(m--) {
scanf("%d%d", &x, &y);
x = a[x], y = a[y];
if(x > y) swap(x, y);
if(!(~ans[x][y])) {
int A = cnt[x], B = cnt[y];
if(x == y) ans[x][y] = 1ll * base * f[n/2] % mod;
else {
if(A + B > n/2) ans[x][y] = 0;
else {
for(int j = 0; j <= n/2; ++j)
g[j] = (f[j] - ((j >= A) ? g[j-A]: 0) + mod) % mod;
for(int j = 0; j <= n/2; ++j)
h[j] = (g[j] - ((j >= B) ? h[j-B]: 0) + mod) % mod;
ans[x][y] = 2ll * base * h[n/2] % mod;
}
}
}
printf("%d\n", ans[x][y]);
}
}

E. Tree

1.5S 256MB

题意

给出一棵树,节点为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_09

,有

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_33

次询问。

每次询问格式为

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_57

。表示询问在以

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_58

为根的情况下,把给出

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_16

个点,分成至多

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_60

组的分配方案数,使得没有一个点和它的祖先在同一个组内。答案膜

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_61

输出。

分析

看到

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_62


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_63

,那么

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_64

的算法一定是可行的。这样的分组方案数一般就是

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_47

,但是由于是给出的点不方便树形

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_47

,我们就直接按顺序

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_47


定义

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_68

表示给定的

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_16

个数中在

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_58

为根的情况下是

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_14

的祖先的点的数量。那么

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_72

一定成立。所以我们按

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_68

排序之后就可以只用考虑当前点不能祖先放在一起,而没有后效性了。

定义

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_74

表示把前

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_14

个点分成了

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_76

组的方案数,由于我们知道

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_14

的祖先们肯定两两不在同一个组内,那么就可以这么写转移方程式:

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_78

我们将

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_#include_76

倒序枚举就能够去掉第一维了。

如何求

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_68


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_68

其实就是

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_14


CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_58

的路径上有效点的数量,这个用

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_大小写_84

维护就行了。不过还是要写个

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解_c++_85


CODE

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 100005;
const int mod = 1e9 + 7;
const int MAXM = 305;
int n, q, k, m, r, f[MAXN], a[MAXN], dp[MAXM];
int dep[MAXN], dfn[MAXN], tmr;
int son[MAXN], fa[MAXN], top[MAXN], sz[MAXN];
vector<int>G[MAXN];
void dfs(int u, int ff) {
dep[u] = dep[fa[u] = ff] + (sz[u] = 1);
for(auto v : G[u])
if(v != ff) {
dfs(v, u), sz[u] += sz[v];
if(sz[v] > sz[son[u]])
son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp; dfn[u] = ++tmr;
if(son[u]) dfs2(son[u], tp);
for(auto v : G[u])
if(v != fa[u] && v != son[u])
dfs2(v, v);
}
inline int lca(int u, int v) {
while(top[u]^top[v]) {
if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
return dep[u] > dep[v] ? v : u;
}
int T[MAXN]; bool vis[MAXN];
inline void upd(int x, int val) {
while(x <= n) T[x] += val, x += x&-x;
}
inline int qsum(int x) { int re = 0;
while(x) re += T[x], x -= x&-x;
return re;
}
inline bool cmp(int A, int B) { return f[A] < f[B]; }
int main () {
scanf("%d%d", &n, &q);
for(int i = 1, x, y; i < n; ++i)
scanf("%d%d", &x, &y),
G[x].push_back(y),
G[y].push_back(x);
dfs(1, 0); dfs2(1, 1);
while(q--) {
scanf("%d%d%d", &k, &m, &r);
for(int i = 1; i <= k; ++i) {
scanf("%d", &a[i]);
int v = a[i];
upd(dfn[v], 1), upd(dfn[v]+sz[v], -1), vis[v] = 1;
}
int qsumr = qsum(dfn[r]);
for(int i = 1; i <= k; ++i) {
int v = a[i], LCA = lca(r, v);
f[v] = qsum(dfn[v]) + qsumr - 2*qsum(dfn[LCA]) + vis[LCA] - 1;
//printf("f[%d] = %d lca(r:%d, v:%d) = %d\n", v, f[v], r, v, LCA);
}
for(int i = 1; i <= k; ++i) {
int v = a[i];
upd(dfn[v], -1), upd(dfn[v]+sz[v], 1), vis[v] = 0;
}
sort(a + 1, a + k + 1, cmp);
for(int j = 0; j <= m; ++j) dp[j] = 0;
dp[0] = 1;
for(int i = 1; i <= k; ++i) {
int v = a[i];
for(int j = min(i, m); j; --j) {
if(j <= f[v]) dp[j] = 0;
else dp[j] = (1ll * dp[j] * (j-f[v]) % mod + dp[j-1]) % mod;
}
dp[0] = 0;
}
int ans = 0;
for(int j = 1; j <= m; ++j)
ans = (ans + dp[j]) % mod;//, printf("dp[%d] = %d\n", j, dp[j]);
printf("%d\n", ans);
}
}