Description
有nn个点,次加边或删边操作,每次操作结束后查询kk匹配的方案数,
Input
第一行输入一整数TT表示用例组数,每组用例首先输入两个整数,之后mm行每行表示一种操作
Output
每次操作后输出n2n2个数字表示kk匹配的方案数,结果模
Sample Input
Sample Output
1 0
2 1
3 1
4 2
3 1
2 1
3 1
4 2
Solution
dp[S]dp[S]表示状态为SS的点集两两匹配的方案数,那么每次加一条边时,考虑所有包含u,vu,v的状态SS,有转移,减边同理,时间复杂度O(m2n)O(m2n)
Code
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 1111
#define mod 1000000007
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int T,n,m,dp[maxn],num[maxn],ans[6];
int main()
{
for(int i=0;i<(1<<10);i++)num[i]=num[i/2]+(i&1);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
int N=1<<n;
while(m--)
{
char op[3];
int u,v;
scanf("%s%d%d",op,&u,&v);
memset(ans,0,sizeof(ans));
u--,v--;
if(op[0]=='+')
{
dp[(1<<u)+(1<<v)]=add(dp[(1<<u)+(1<<v)],1);
for(int S=N-1;S>=(1<<u)+(1<<v);S--)
if(((S>>u)&1)&&((S>>v)&1)&num[S]%2==0)
dp[S]=add(dp[S],dp[S-(1<<u)-(1<<v)]);
for(int S=0;S<N;S++)
if(num[S]%2==0)ans[num[S]/2]=add(ans[num[S]/2],dp[S]);
for(int i=1;i<=n/2;i++)
printf("%d%c",ans[i],i==n/2?'\n':' ');
}
else
{
dp[(1<<u)+(1<<v)]=add(dp[(1<<u)+(1<<v)],mod-1);
for(int S=N-1;S>=(1<<u)+(1<<v);S--)
if(((S>>u)&1)&&((S>>v)&1)&num[S]%2==0)
dp[S]=add(dp[S],mod-dp[S-(1<<u)-(1<<v)]);
for(int S=0;S<N;S++)
if(num[S]%2==0)ans[num[S]/2]=add(ans[num[S]/2],dp[S]);
for(int i=1;i<=n/2;i++)
printf("%d%c",ans[i],i==n/2?'\n':' ');
}
}
}
return 0;
}