*题解:CF1679F Formalism for Formalism
解析
要求等价类数目,那就给每个等价类找一个代表元,问题变为求代表元数目,不妨令字典序最小的那个为一个等价类的代表元。
考虑 DP,设 \(f_{i,j}\) 表示考虑了前 \(i\) 位,第 \(i\) 位为 \(j\),的代表元数目,枚举下一位的数 \(k\) 进行转移,我们只应该统计不会产生交换的方案数,其中不会产生交换即不存在数对 \((j,k)\) 或 \(j \le k\),只有这些方案才合法。
然而这样还是不行,因为可能出现连续的交换导致枚举的下一位 \(k\) 可以跑到更前面的 \(j'\) 的前面,其中 \(j' > k\),这样做的字典序最小,但若此时有 \(j \le k\),我们就会认为不会产生交换。
故更改状态,我们想要知道有哪些下一位的取值是合法的,故设 \(f_{i,S}\) 表示考虑了前 \(i\) 位,下一位可选集合为 \(S\) 时的方案数。若下一位选了 \(x\),那么对于 \(y\),其应当被加进新集合 \(S'\) 里的充要条件是:不存在数对 \((x,y)\),或者 \(y \ge x\) 且 \(y\in S\)。要求 \(y \in S\) 就是为了防止连续交换的情况。
预处理每个 \(S\) 能转移到的 \(S'\),总时间复杂度 \(O(nV2^V)\)。
总结
遇到等价类问题尝试寻找代表元。
代码
/*
*/
#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 10) + 5,M = 5e4 + 5,mod = 998244353;
typedef long long ll;
typedef pair<int,int> pii;
vector<int> ns[N];
int g[15][15],f[M][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// freopen("fa.in","r",stdin);
// freopen("fa.out","w",stdout);
int n;
cin>>n;
int m;
cin>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
g[u][v] = g[v][u] = true;
}
for(int i=0;i<(1 << 10);i++){
for(int x=0;x<=9;x++){
if(!(i & (1 << x))) continue;
int j = 0;
for(int y=0;y<=9;y++){
if(!g[x][y] || (y >= x && (i & (1 << y)))){
j |= 1 << y;
}
}
ns[i].push_back(j);
}
}
f[0][(1 << 10) - 1] = 1;
for(int i=0;i<n;i++){
for(int s=0;s<(1 << 10);s++)if(f[i][s]){
for(int ss : ns[s]){
f[i + 1][ss] = (f[i + 1][ss] + f[i][s]) % mod;
}
}
}
int res = 0;
for(int s=0;s<(1 << 10);s++){
res = (res + f[n][s]) % mod;
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号