Codeforces 979E Kuro and Topological Parity dp+组合数

真是差一点点就整出来转移方程了,这个方程也不咋难想的呀。假设每一次都把新的点加在了旧点后面。为什么是加在后面,不是多算加在前面,也不算加在中间?其实算加在前面也无妨,只是一定只能算成加载某一固定位置,因为这三种加法出来的状态数互相重叠的,单算一种则不会。这一第一个阻碍我想出转移方程的地方。

然后就按部就班了,各个状态分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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值