CF65A Harry Potter and Three Spells
考察严谨的思维与特判
如果
d
=
0
d = 0
d=0那么永远不会有金子
在
d
!
=
0
d !=0
d!=0的情况下,如果
c
=
0
c=0
c=0,那么会有无限多的金子
在
c
,
d
!
=
0
c, d != 0
c,d!=0 的情况下,如果
b
=
0
b = 0
b=0 那么不会有铅
在
b
,
c
,
d
!
=
0
b, c, d != 0
b,c,d!=0 的情况下,如果
a
=
0
a = 0
a=0 那么会有无限多的铅
在
a
,
b
,
c
,
d
!
=
0
a, b, c,d!=0
a,b,c,d!=0 的情况下,如果
f
=
0
f = 0
f=0 那么不会有无限多的沙子
在
a
,
b
,
c
,
d
,
f
!
=
0
a, b, c, d, f!=0
a,b,c,d,f!=0的情况下,如果
e
=
0
e = 0
e=0 那么会有无限多的沙子
CF715E Complete the Permutations
首先答案为 n - 环的个数,因为大小为
l
e
n
len
len 的环需要交换
l
e
n
−
1
len-1
len−1 次
考虑全部为 0 的情况:对于每一种方案,都可以通过交换让第一个排列为
1
,
2
,
3
,
.
.
.
,
n
1,2,3,...,n
1,2,3,...,n,于是有 k 个环的方案就是
S
n
,
k
∗
n
!
S_{n,k}*n!
Sn,k∗n!,
S
S
S为一类斯特林
然后发现存在以下几种情况
1.环的两头都不定
?
,
x
1
,
x
2
,
.
.
.
,
x
n
,
?
?,x_1,x_2,...,x_n,?
?,x1,x2,...,xn,?,不妨定为 A
在原序列上长成这样:
x
1
,
x
2
,
x
3
.
.
.
,
x
n
x_1,x_2,x_3...,x_n
x1,x2,x3...,xn
x
2
,
x
3
,
x
4
,
.
.
.
,
x
n
+
1
x_2,x_3,x_4,...,x_{n+1}
x2,x3,x4,...,xn+1
2.环有一头定
?
,
x
1
,
x
2
,
.
.
.
,
x
n
?,x_1,x_2,...,x_n
?,x1,x2,...,xn,或
x
1
,
x
2
,
.
.
.
,
x
n
,
?
x_1,x_2,...,x_n,?
x1,x2,...,xn,?,不妨定为 B,C
在原序列长这样:
x
1
,
x
2
,
.
.
.
,
x
n
x_1,x_2,...,x_n
x1,x2,...,xn
x
2
,
x
3
,
.
.
.
,
0
x_2,x_3,...,0
x2,x3,...,0
0
,
x
1
,
.
.
.
,
x
n
0,x_1,...,x_n
0,x1,...,xn
x
1
,
x
2
,
.
.
.
,
x
n
+
1
x_1,x_2,...,x_{n+1}
x1,x2,...,xn+1
3.两头都定
x
1
,
x
2
,
.
.
.
,
x
n
x_1,x_2,...,x_n
x1,x2,...,xn,不妨定为 D
在原序列长这样:
0
,
x
1
,
.
.
.
,
x
n
0,x_1,...,x_n
0,x1,...,xn
x
1
,
x
2
,
.
.
.
,
0
x_1,x2,...,0
x1,x2,...,0
然后发现一些性质,A,B,C可以形成自环
B:在0位填上下一个的
x
1
x_1
x1 即可
C:在0位填上上一个的
x
n
+
1
x_{n+1}
xn+1 即可
B 可以跟 A,B 接,C 可以跟 A,C 接,B,C 如果要接需要一个 A 接在两头
接着发现,我们事先将序列的两个位置交换一下答案是不会变的
于是考虑将序列重新按 A,B,C,D 的顺序重排,先将 A 类形成一些环,然后将每一类依次插进去
f
i
,
j
f_{i,j}
fi,j表示考虑前 i 个,有 j 个环的方案
对于 A,B 类
f
i
,
j
=
f
i
−
1
,
j
−
1
+
(
i
−
1
)
∗
f
i
−
1
,
j
f_{i,j}=f_{i-1,j-1}+(i-1)*f_{i-1,j}
fi,j=fi−1,j−1+(i−1)∗fi−1,j
对于 C 类,不能接 B
f
i
,
j
=
f
i
−
1
,
j
−
1
+
(
i
−
1
−
B
)
∗
f
i
−
1
,
j
f_{i,j}=f_{i-1,j-1}+(i-1-B)*f_{i-1,j}
fi,j=fi−1,j−1+(i−1−B)∗fi−1,j
对于 D 类,不能接A后,不能接B前,不能接自己的两边,不能成环
f
i
,
j
=
f
i
−
1
,
j
∗
(
i
−
1
−
B
−
C
−
D
∗
2
)
f_{i,j}=f_{i-1,j}*(i-1-B-C-D*2)
fi,j=fi−1,j∗(i−1−B−C−D∗2)
对于原序列
(
0
,
0
)
(0,0)
(0,0)的位置,可以交换顺序,于是乘上
c
n
t
!
cnt!
cnt!
法2:
设
f
i
f_i
fi为第B类组成 i 个环的方案数,由于
A
+
B
=
B
A+B = B
A+B=B,选 j 条出来成环,剩下的插到 A 类里面去
f
i
=
∑
j
=
i
B
S
j
,
i
(
B
j
)
(
B
−
j
+
A
−
1
)
!
(
A
−
1
)
!
f_i=\sum_{j=i}^BS_{j,i}\binom{B}{j}\frac{(B-j+A-1)!}{(A-1)!}
fi=∑j=iBSj,i(jB)(A−1)!(B−j+A−1)!
g
i
g_i
gi 表示第 C 类组成 i 个环的方案数,与
f
i
f_i
fi 同理
设
h
i
h_i
hi为第 A 类的方案数,
h
i
=
S
A
,
i
∗
A
!
h_i=S_{A,i}*A!
hi=SA,i∗A!
#include<bits/stdc++.h>
#define N 2005
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
const int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod;}
void Add(int &a, int b){ a = add(a, b); }
int n, k, m, cc;
int ans[N], cnt[N];
int a[N], b[N];
int tg[N], flg[N], vis[N], s[N];
vector<int> v[N], seq;
int f[N][N];
void dfs(int u){
if(vis[u]) return; vis[u] = 1; seq.push_back(u);
for(int i = 0; i < v[u].size(); i++) dfs(v[u][i]);
}
int main(){
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++) b[i] = read();
for(int i = 1; i <= n; i++){
if(a[i] && !b[i]) tg[a[i]] |= 1;
if(!a[i] && b[i]) tg[b[i]] |= 2;
if(a[i] && b[i]) v[a[i]].push_back(b[i]), flg[b[i]] = 1;
if(!a[i] && !b[i]) ++k;
}
for(int i = 1; i <= n; i++){
if(!vis[i] && !flg[i]){
seq.clear();
dfs(i); m++;
if(tg[seq.back()] & 1) s[m] |= 1;
if(tg[seq[0]] & 2) s[m] |= 2;
cnt[s[m]]++;
}
}
for(int i = 1; i <= n; i++) if(!vis[i]) dfs(i), ++cc; // circle
f[0][0] = 1;
for(int i = 1; i <= cnt[0]; i++){
for(int j = 0; j <= i; j++){
Add(f[i][j + 1], f[i - 1][j]);
Add(f[i][j], mul(i - 1, f[i - 1][j]));
}
}
for(int i = cnt[0] + 1; i <= cnt[0] + cnt[1]; i++){
for(int j = 0; j <= i; j++){
Add(f[i][j + 1], f[i - 1][j]);
Add(f[i][j], mul(i - 1, f[i - 1][j]));
}
}
for(int i = cnt[0] + cnt[1] + 1; i <= cnt[0] + cnt[1] + cnt[2]; i++){
for(int j = 0; j <= i; j++){
Add(f[i][j + 1], f[i - 1][j]);
Add(f[i][j], mul(i - cnt[1] - 1, f[i - 1][j]));
}
}
int sum = cnt[0] + cnt[1] + cnt[2];
for(int i = sum + 1; i <= sum + cnt[3]; i++){
for(int j = 0; j <= i; j++){
Add(f[i][j], mul(max(0, i - 1 - (i - sum - 1) * 2 - cnt[1] - cnt[2]), f[i-1][j]));
}
}
for(int i = max(0, 1 - cc); i <= n - cc; i++) ans[n - (i + cc)] = f[m][i];
for(int i = 0; i < n; i++) for(int j = 1; j <= k; j++) ans[i] = mul(ans[i], j);
for(int i = 0; i < n; i++) cout << ans[i] << " "; return 0;
}
CF65D Harry Potter and the Sorting Hat
只要有一丁丁概率就可以作为答案
于是 用
f
a
,
b
,
c
,
d
f_{a,b,c,d}
fa,b,c,d 记录
a
,
b
,
c
,
d
a, b, c, d
a,b,c,d 这种状态合不合法,可以拿 30 pts
然后信仰地发现状态数应该很少,由于题目总是先加最小的限制,一个状态 a,它能达到的最小值跟最大值相差可能也不是很大,也就是说总的状态数是远远不及
n
4
n^4
n4 的
于是记忆化搜索一波就过了
#include<bits/stdc++.h>
#define N 10050
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1;}
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
int T, n; char s[N];
struct Node{
int a, b, c, d;
bool operator < (const Node &A) const {
return a < A.a || (a == A.a && b < A.b) || (a == A.a && b == A.b && c < A.c)
|| (a == A.a && b == A.b && c == A.c && d < A.d);
}
};
map<Node, bool> mp;
int flg[4];
void dfs(int u, int a, int b, int c){
int d = u - a - b - c;
Node now = (Node){a, b, c, d};
if(mp[now]) return; mp[now] = 1;
if(u == n){
int mi = min(min(a, b), min(c, d));
if(a == mi) flg[0] = 1;
if(b == mi) flg[1] = 1;
if(c == mi) flg[2] = 1;
if(d == mi) flg[3] = 1;
return;
}
if(s[u + 1] == '?'){
int mi = min(min(a, b), min(c, d));
if(a == mi) dfs(u + 1, a + 1, b, c);
if(b == mi) dfs(u + 1, a, b + 1, c);
if(c == mi) dfs(u + 1, a, b, c + 1);
if(d == mi) dfs(u + 1, a, b, c);
}
else{
if(s[u + 1] == 'G') dfs(u + 1, a + 1, b, c);
if(s[u + 1] == 'H') dfs(u + 1, a, b + 1, c);
if(s[u + 1] == 'R') dfs(u + 1, a, b, c + 1);
if(s[u + 1] == 'S') dfs(u + 1, a, b, c);
}
}
int main(){
T = read();
while(T--){
n = read(); scanf("%s", s + 1);
mp.clear(); memset(flg, 0, sizeof(flg));
dfs(0, 0, 0, 0);
if(flg[0]) puts("Gryffindor");
if(flg[1]) puts("Hufflepuff");
if(flg[2]) puts("Ravenclaw");
if(flg[3]) puts("Slytherin");
puts("");
}
}