CSP-S 模拟 19/10/02

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 len1
考虑全部为 0 的情况:对于每一种方案,都可以通过交换让第一个排列为 1 , 2 , 3 , . . . , n 1,2,3,...,n 1,2,3,...,n,于是有 k 个环的方案就是 S n , k ∗ n ! S_{n,k}*n! Sn,kn! 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=fi1,j1+(i1)fi1,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=fi1,j1+(i1B)fi1,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=fi1,j(i1BCD2)
对于原序列 ( 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)(A1)!(Bj+A1)!
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,iA!


#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("");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值