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;
}
posted @ 2026-10-19 18:02  farenara_sayowell  阅读(4)  评论(0)    收藏  举报