真是差一点点就整出来转移方程了,这个方程也不咋难想的呀。假设每一次都把新的点加在了旧点后面。为什么是加在后面,不是多算加在前面,也不算加在中间?其实算加在前面也无妨,只是一定只能算成加载某一固定位置,因为这三种加法出来的状态数互相重叠的,单算一种则不会。这一第一个阻碍我想出转移方程的地方。
然后就按部就班了,各个状态分4维,又偶数个链的白点,偶数个链的黑点,奇数个链的白点,奇数个链的黑点。单个点就是奇数链。这个明明很清楚明白,然而却是阻碍我想出转移方程的第二个地方。
以上的地方都弄好了,就相当于已经把转移方程写出来了。然后,那4维的数该怎么算呢?在这里我又犯了傻,统计了黑白点的个数,再又加又减的。但其实做转移的时候直接假设再从小到大枚举点就行了。
各个边界条件,是否为0,要想清楚,否则就会像我一样处处爆0。
#include<iostream>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
int n,p,a[60];
long long f[60][60][60][60],pow[60];
const long long mod=1000000007;
int main()
{
scanf("%d%d",&n,&p);
pow[0]=1;
for (int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
pow[i]=(pow[i-1]*2)%mod;
}
memset(f,0,sizeof(f));
f[0][0][0][0]=1;
long long ans=0;
for (int i=1; i<=n; i++)
{
for (int x1=0; x1<=i; x1++)
{
for (int x2=0; x2<=i-x1; x2++)
{
for (int y1=0; y1<=i-x1-x2; y1++)
{
int y2=i-x1-x2-y1;
if (x1+y1>=0 && (a[i]==-1 || a[i]==1) )
{
long long tmp=0;
if (y1)
{
if (y2)
{
tmp=(tmp+f[i-1][x1][x2][y1-1]*pow[y2-1]%mod)%mod;
}else
{
tmp= (tmp+f[i-1][x1][x2][y1-1]);
}
}
if (x1 && y2)
{
tmp=(tmp+f[i-1][x1-1][x2][y1]*pow[y2-1]%mod)%mod;
}
f[i][x1][x2][y1]=(f[i][x1][x2][y1]+tmp*pow[x1+x2+y1-1]%mod)%mod;
}
if (x2+y2 && (a[i]==0 || a[i]==-1) )
{
long long tmp=0;
if (y2)
{
if (y1)
{
tmp=(tmp+f[i-1][x1][x2][y1]*pow[y1-1]%mod)%mod;
}else
{
tmp=(tmp+f[i-1][x1][x2][y1]);
}
}
if (x2 && y1)
{
tmp=(tmp+f[i-1][x1][x2-1][y1]*pow[y1-1]%mod)%mod;
}
f[i][x1][x2][y1]=(f[i][x1][x2][y1]+tmp*pow[x2+y2+x1-1]%mod)%mod;
}
if (i==n && (y1+y2)%2==p)
{
ans=(ans+f[i][x1][x2][y1])%mod;
}
}
}
}
}
printf("%lld\n",ans);
return 0;
}