题目:给你n个点,m个操作,每种操作要么加一条边要么减一条边,紧接着询问当前选出1条无公共端点的边,2条无公共端点的边,3条.....n/2条无公共端点边时分别有多少种不同的选择。(n<=10)
思路:真是刺激,比赛时想到了状压没想到怎么搞,然后疯狂算暴力的复杂度。感觉还可以,应该不会T。交了一发,疯狂刷新后结果TLE。然后发现还可以优化下常数,直接把下面的代码写到init里面预处理出4条边和五条边的所有情况,然后ac(3650MS)。 题目只需要考虑新加(减)一条边的影响就可以了,别的方案都在上一步算过了。
状压复杂度O(m*2^n),暴力我算的大约是 常数2*1e3*m,貌似稍微慢一点。。。贴个代码。之后补上状压的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int t,n,m;
ll a[11][11],ans[10];
vector<int>px[7][11][11],py[7][11][11];
void init(int n)
{
for(int x=1;x<=n;x++)
for(int y=x+1;y<=n;y++)
{
int nu=0;
if(n>=8)//4
{
int book[11]={0};
book[x]=book[y]=1;
for(int i=1;i<=n-5;i++)
if(!book[i])
{
book[i]=1;
for(int j=i+1;j<=n;j++)
if(!book[j])
{
book[j]=1;
for(int ii=i+1;ii<=n-3;ii++)
if(!book[ii])
{
book[ii]=1;
for(int jj=ii+1;jj<=n;jj++)
if(!book[jj])
{
book[jj]=1;
for(int iii=ii+1;iii<=n-1;iii++)
if(!book[iii])
{
book[iii]=1;
for(int jjj=iii+1;jjj<=n;jjj++)
if(!book[jjj])
{
nu++;
px[4][x][y].push_back(i);
px[4][x][y].push_back(ii);
px[4][x][y].push_back(iii);
py[4][x][y].push_back(j);
py[4][x][y].push_back(jj);
py[4][x][y].push_back(jjj);
// (ans[4]+=flag*(a[i][j]*a[ii][jj]%mod*a[iii][jjj]%mod)+mod)%=mod;
}
book[iii]=0;
}
book[jj]=0;
}
book[ii]=0;
}
book[j]=0;
}
book[i]=0;
}
}
// cout<<nu<<endl;
// cout<<uu<<endl;
if(n>=10)//5
{
int book[11]={0};
book[x]=book[y]=1;
for(int i=1;i<=n-7;i++)
if(!book[i])
{
book[i]=1;
for(int j=i+1;j<=n;j++)
if(!book[j])
{
book[j]=1;
for(int ii=i+1;ii<=n-5;ii++)
if(!book[ii])
{
book[ii]=1;
for(int jj=ii+1;jj<=n;jj++)
if(!book[jj])
{
book[jj]=1;
for(int iii=ii+1;iii<=n-3;iii++)
if(!book[iii])
{
book[iii]=1;
for(int jjj=iii+1;jjj<=n;jjj++)
if(!book[jjj])
{
book[jjj]=1;
for(int i4=iii+1;i4<=n-1;i4++)
if(!book[i4])
{
book[i4]=1;
for(int j4=i4+1;j4<=n;j4++)
if(!book[j4])
{
px[5][x][y].push_back(i);
px[5][x][y].push_back(ii);
px[5][x][y].push_back(iii);
px[5][x][y].push_back(i4);
py[5][x][y].push_back(j);
py[5][x][y].push_back(jj);
py[5][x][y].push_back(jjj);
py[5][x][y].push_back(j4);
}
book[i4]=0;
}
book[jjj]=0;
}
book[iii]=0;
}
book[jj]=0;
}
book[ii]=0;
}
book[j]=0;
}
book[i]=0;
}
}
}
//cout<<px[4][1][5].size()<<endl;
//cout<<px[5][1][2].size()<<endl;
}
int main()
{
scanf("%d",&t);
init(10);
while(t--)
{
memset(a,0,sizeof a);
memset(ans,0,sizeof ans);
scanf("%d%d",&n,&m);
while(m--)
{
char s[2];
int x,y;
scanf("%s%d%d",s,&x,&y);
ll flag=(s[0]=='+'?1:-1);
if(x>y) swap(x,y);
a[x][y]+=flag;
ans[1]+=flag;///1
if(n>=4)///2
{
for(int i=1;i<=n-1;i++)
if(i!=x&&i!=y)
{
for(int j=i+1;j<=n;j++)
if(j!=x&&j!=y)
(ans[2]+=flag*a[i][j]+mod)%=mod;
}
}
int nn=0;
if(n>=6)///3
{
int book[11]={0};
book[x]=book[y]=1;
for(int i=1;i<=n-3;i++)
if(!book[i])
{
book[i]=1;
for(int j=i+1;j<=n;j++)
if(!book[j])
{
book[j]=1;
for(int ii=i+1;ii<=n-1;ii++)
if(!book[ii])
{
book[ii]=1;
for(int jj=ii+1;jj<=n;jj++)
if(!book[jj])
{
nn++;
(ans[3]+=flag*(a[i][j]*a[ii][jj]%mod)+mod)%=mod;
}
book[ii]=0;
}
book[j]=0;
}
book[i]=0;
}
}
// cout<<nn<<endl;
if(n>=8)
{
for(int i=0;i<px[4][x][y].size();i+=3)
{
int i1=px[4][x][y][i];
int i2=px[4][x][y][i+1];
int i3=px[4][x][y][i+2];
int j1=py[4][x][y][i];
int j2=py[4][x][y][i+1];
int j3=py[4][x][y][i+2];
(ans[4]+=flag*(a[i1][j1]*a[i2][j2]%mod*a[i3][j3]%mod)+mod)%=mod;
}
}
if(n>=10)
{
for(int i=0;i<px[5][x][y].size();i+=4)
{
int i1=px[5][x][y][i];
int i2=px[5][x][y][i+1];
int i3=px[5][x][y][i+2];
int i4=px[5][x][y][i+3];
int j1=py[5][x][y][i];
int j2=py[5][x][y][i+1];
int j3=py[5][x][y][i+2];
int j4=py[5][x][y][i+3];
(ans[5]+=flag*(a[i1][j1]*a[i2][j2]%mod*a[i3][j3]%mod*a[i4][j4]%mod)+mod)%=mod;
}
}
for(int i=1;i<=n/2;i++)
{
if(i<n/2)
printf("%d ",ans[i]);
else printf("%d\n",ans[i]);
}
}
}
return 0;
}
好长的代码,下面是状压的做法(3478MS),dp[i][s]表示到达i步,用s状态的点时,有多少种方案。状压就不用考虑具体的匹配是什么样子的啦。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll dp[2][1<<10],ans[11];
int t,n,m;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(dp,0,sizeof dp);
dp[0][0]=1;
for(int i=1;i<=m;i++)
{
int x,y; char str[2];
scanf("%s%d%d",str,&x,&y);
x--,y--;
ll flag=(str[0]=='+')?1:-1;
for(int s=0;s<(1<<n);s++)
{
dp[i&1][s]=dp[(i-1)&1][s];
if((s&(1<<x))&&(s&(1<<y)))
(dp[i&1][s]+=flag*dp[(i-1)&1][s^(1<<x)^(1<<y)]+mod)%=mod;
}
memset(ans,0,sizeof ans);
for(int s=0;s<(1<<n);s++)
{
int k=__builtin_popcount(s);
(ans[k]+=dp[i&1][s])%=mod;
}
printf("%lld",ans[2]);
for(int i=4;i<=n;i+=2)
printf(" %lld",ans[i]);
puts("");
}
}
return 0;
}