题目:http://acm.hdu.edu.cn/showproblem.php?pid=6321
题意:
n个点,m个操作;
每次操作可以加边或减边;
每次操作后输出包含1,2,…,n/2条边的合法方案数;
一个合法方案要求:所有边的连接的顶点不能有重复的;
分析:
状压状态为S
加边时:f[S]+=f[S-(1<< u)-(1<< v)]
减边时:f[S] -=f[S-(1<< u)-(1<< v)]
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=2005;
const ll MOD=1e9+7;
ll f[tmax],ans[20];
int n;
int main()
{
int T,m,i,j,u,v;
char ch;
cin>>T;
while(T--)
{
memset(f,0,sizeof(f));
f[0]=1;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
getchar();
ch=getchar();
scanf("%d%d",&u,&v);
if(ch=='+') for(j=(1<<10)-1;j>=0;j--)
{
if((j&(1<<(u-1)))==0) continue;
if((j&(1<<(v-1)))==0) continue;
f[j]=(f[j]+f[j-(1<<(u-1))-(1<<(v-1))])%MOD;
}
else for(j=(1<<10)-1;j>=0;j--)
{
if((j&(1<<(u-1)))==0) continue;
if((j&(1<<(v-1)))==0) continue;
f[j]=((f[j]-f[j-(1<<(u-1))-(1<<(v-1))])%MOD+MOD)%MOD;
}
memset(ans,0,sizeof(ans));
for(j=(1<<10)-1;j>=0;j--)
{
int num=__builtin_popcount(j);
ans[num]=(ans[num]+f[j])%MOD;
}
for(j=1;j<n/2;j++)
printf("%I64d ",ans[j*2]);
printf("%I64d\n",ans[n]);
}
}
return 0;
}