zoukankan      html  css  js  c++  java
  • CF979E

    非常好的dp,非常考dp的能力

    很显然是个计数问题,那么很显然要么是排列组合,要么是递推,这道题很显然递推的面更大一些。

    那么我们来设计一下状态:

    设状态f[i][j][k][p]表示目前到了第i个点,这i个点中有j个白点是奇数条好的路径的结尾,k个黑点是奇数条好的路径的结尾,p个白点是偶数条好的路径的结尾的方案数

    可能这个状态本身不是特别好懂,我们详细解释一下:

    这样的图的个数会取决于好的路径的条数,而好的路径的条数又可以分成两类:以黑点为结尾和以白点为结尾

    那么对于每一个黑点或白点,他只有两种可能:有奇数条好的路径在这结尾和有偶数条好的路径在这结尾。

    这样我们就将整个图的点分为了4类:白点是奇数条好的路径的结尾,黑点是奇数条好的路径的结尾,白点是偶数条好的路径的结尾,黑点是偶数条好的路径的结尾。

    我们将其中三种扔进状态里,而第四个就可以算出来。

    接着我们考虑转移:

    分类转移:如果一个节点是白色,那么一个合法的路径一定会从上一个黑点转过来。

    而且如果想要影响这个白点奇偶性,上面一定会连上一个奇数黑点,因为偶数黑点对这个白点的奇偶性没有影响。

    我们讨论这个白点是奇数白点还是偶数白点:如果这个白点是奇数白点,那么从上面的奇数黑点转过来时,要连1个,3个...奇数个,这样才能保证这个白点是奇数的。

    那么如果设之前奇数黑点的数量为k,总方案数即为large C_{k}^{1}+C_{k}^{3}+C_{k}^{5}+....=2^{k-1}

    利用这一点,乘原来方案数转移即可

    那么这个白点是偶数白点的转移也同理,总方案数即为large C_{k}^{0}+C_{k}^{2}+C_{k}^{4}+....=2^{k-1}

    同理转移即可

    最后,考虑其他点:由于别的点对这个白点的奇偶性没有影响,所以对于别的点可以随便连,也就是2^别的点的个数,乘这个东西即可

    那么黑点也就同理了。

    贴代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    #define mode 1000000007
    using namespace std;
    ll dp[55][55][55][55];//到了第几个点,奇数白点,奇数黑点,偶数白点 
    int n,typ;
    int c[55];
    ll mul[55];
    int main()
    {
    	scanf("%d%d",&n,&typ);
    	mul[0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&c[i]);//0黑1白-1任意 
    		mul[i]=(mul[i-1]<<1)%mode;
    	}
    	ll ret=0;
    	if(c[1]==0||c[1]==-1)
    	{
    		dp[1][0][1][0]=1; 
    		if(typ==1&&n==1)
    		{
    			ret++;
    		}
    	}
    	if(c[1]==1||c[1]==-1)
    	{
    		dp[1][1][0][0]=1;
    		if(typ==1&&n==1)
    		{
    			ret++;
    		}
    	}
    	for(int i=2;i<=n;i++)
    	{
    		for(int j=0;j<=i;j++)//奇数白 
    		{
    			for(int k=0;k+j<=i;k++)//奇数黑 
    			{
    				for(int p=0;j+k+p<=i;p++)//偶数白 
    				{
    					int t=i-j-k-p;//偶数黑 
    					if(c[i]==1||c[i]==-1)
    					{
    						ll s=0;
    						if(j+p)
    						{
    							if(j)
    							{
    								if(!k)
    								{
    									s+=dp[i-1][j-1][k][p];
    								}else
    								{
    									s+=mul[k-1]*dp[i-1][j-1][k][p]%mode;
    								}
    								s%=mode;
    							}
    							if(p)
    							{
    								if(k)
    								{
    									s+=mul[k-1]*dp[i-1][j][k][p-1]%mode;	
    								}
    								s%=mode;
    							}							
    						}
    						s*=mul[j+p+t-1];
    						s%=mode;
    						dp[i][j][k][p]+=s;
    						dp[i][j][k][p]%=mode;
    					}
    					if(c[i]==0||c[i]==-1)
    					{
    						ll s=0;
    						if(k+t)
    						{
    							if(k)
    							{
    								if(!j)
    								{
    									s+=dp[i-1][j][k-1][p];
    								}else
    								{
    									s+=mul[j-1]*dp[i-1][j][k-1][p]%mode;
    								}
    								s%=mode;
    							}
    							if(t)
    							{
    								if(j)
    								{
    									s+=mul[j-1]*dp[i-1][j][k][p]%mode;	
    								}
    								s%=mode;
    							}							
    						}
    						s*=mul[k+p+t-1];
    						s%=mode;
    						dp[i][j][k][p]+=s;
    						dp[i][j][k][p]%=mode;
    					}
    					if(i==n)
    					{
    						if((j+k)%2==typ)
    						{
    							ret+=dp[i][j][k][p];
    							ret%=mode;
    						}
    					}
    				}
    			}
    		}
    	}
    	printf("%lld
    ",ret);
    	return 0;
    }
  • 相关阅读:
    团队编程
    灯塔 ——团队展示
    碎阅创造营——项目系统设计与数据库设计
    碎阅创造营——项目需求分析
    碎阅创造营——团队编程
    碎阅创造营——团队展示
    Computer-Hunters——项目系统设计与数据库设计
    Computer-Hunters——项目需求分析
    2019软工实践——第一次团队编程作业
    Computer-Hunters——团队展示
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764149.html
Copyright © 2011-2022 走看看