CF1679F Formalism for Formalism 题解
CF1679F Formalism for Formalism
把能转换成同一个数的数成为一个等价类,我们要求的就是等价类的个数。
考虑把一个等价类用其中字典序最小的数来代表,则我们只要规避不合法的情况来计数就行了,这样就可做很多。
考虑什么情况下是不合法的,若当前有一位是 \(i\),前面第若干位是 \(j\),\(i<j\),那么如果 \(i\) 可以一路交换过去到 \(j\) 前面,则这个数不合法。
设 \(w_i\) 表示可以和 \(i\) 交换的数的集合,\(una_i\) 表示可以和 \(i\) 交换的数里比 \(i\) 小的数的集合,即最直接的不能放在 \(i\) 后面的数。
考虑状压 DP,设 \(f_{i,S}\) 表示填了 \(i\) 位,此时不能选的数的集合为 \(S\) 的方案数。初始 \(f_{0,0}=1\)。转移先要枚举下一位填的数 \(j\),要求 \(j \notin S\),那么现在不能选的数有哪些呢?首先,在 \(S\) 里的数如果能和 \(j\) 交换,那下一位还是不能选这些数,否则直接换过来了。所以非法集合先变为 \(S \land w_j\),再加上 \(j\) 追加的不能选的数,变为 \((S \land w_j) | una_j\)。所以有转移 \(f_{i,(S\land w_j)|una_j} \leftarrow f_{i-1,S}\)。
时间复杂度 \(O(n2^{10}\times 10)\)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
int T,n,m;
const int N = 5e4+10,mod=998244353;
int w[N],una[N];
bitset<11>vis[11];
int f[N],g[N];
inline void add(int &x,int y){
x=(x+y>=mod)?x+y-mod:x+y;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
vis[u][v]=vis[v][u]=1;
}
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++)w[i]|=(vis[i][j]<<j);
for(int j=0;j<i;j++)una[i]|=(vis[i][j]<<j);
}
f[0]=1;
for(int i=1;i<=n;i++){
for(int s=0;s<(1<<10);s++)g[s]=f[s],f[s]=0;
for(int s=0;s<(1<<10);s++){
for(int j=0;j<=9;j++){
if(!(s>>j&1)){
int nw=(s&w[j])|una[j];
add(f[nw],g[s]);
}
}
}
}
int ans=0;
for(int s=0;s<(1<<10);s++){
add(ans,f[s]);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号