速速让我退役
首先要做过这道题 [CEOI2019] Amusement Park 。
然后发现上面那道题的做法直接套是不行的,因为有情况 3 3 3。枚举拆分数肯定是没前途的,这个想都不用想。我还真想了。
仔细思考发现这道题目几乎等价于无向图边定向的 D A G DAG DAG计数。唯一的区别是枚举的入度为 0 0 0的集合似乎不再要求是一个简单的独立集了。
发现问题出在容斥系数上面。怎么改就对了?我们发现把独立集的大小看成连通块的数目就好了。
证明后面再补。这题出的挺好的,考察的角度比较深入。
复杂度 O ( 3 n + 2 n × n 2 ) O(3^n+2^n\times n^2) O(3n+2n×n2)。
remark \text{remark} remark 说实话还是观察了很久才胡出这个结论。
#include
#define fi first
#define se second
#define ll long long
#define pb push_back
#define db double
#define inf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
using namespace std;
const int mod=998244353;
ll fpow(ll x,ll y=mod-2){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}return z;
}
void add(ll &x,ll y){
x=(x+y)%mod;
}
int lowbit(int x){return x&-x;}
int n,m,U[1005],ct[1<<17],V[1005],fa[17];
ll f[1<<17];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;for(int i=0;i<m;i++)cin>>U[i]>>V[i],U[i]--,V[i]--;
for(int i=1;i<1<<n;i++){
for(int j=0;j<n;j++){
if(i>>j&1)fa[j]=j,ct[i]++;
}
for(int j=0;j<m;j++){
if((i>>U[j]&1)&&(i>>V[j]&1)&&find(U[j])!=find(V[j]))fa[fa[U[j]]]=fa[V[j]],ct[i]--;
}
}
f[0]=1;
for(int s=1;s<1<<n;s++){
for(int s2=s;s2;s2=(s2-1)&s){
if(ct[s2]&1)add(f[s],f[s-s2]);
else add(f[s],-f[s-s2]);
}
}
cout<<(f[(1<<n)-1]+mod)%mod;
}