zoukankan      html  css  js  c++  java
  • P2182 翻硬币 DP

    题意:

    给定一个01序列,有K次操作,每次可以将M个元素翻转,给定初始初始状态和终止状态,求方案数

    范围&性质:$1\le n\le 100,0\le k\le 100,0\le m\le n $

    分析:

    由于翻转不要求顺序,所以位置对方案没有任何影响,我们自然而然可以将点分为两类:与目标状态相同,与目标状态相反

    然后我们可以设计DP状态,\(f[i][j]\)表示进行了\(i\)次操作有\(j\)个元素和目标状态不一样,推导出DP方程如下:

    \[f[i][j-l+k-l]=\sum_{l=0}^k f[i-1][j]\times C_j^l\times C_{n-j}^{k-l} \]

    表示第\(i\)次操作,减少了\(l\)个,增加了\(k-l\)个,最后的答案为\(f[k][0]\)

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const long long mod= 1e9+7;
    	long long n,k,m,cnt=0;
    	long long f[105][105],c[105][105];
    	char a[105],b[105];
    	
    	void init()
    	{
    		c[0][0]=1;
    		c[1][0]=c[1][1]=1;
    		for(int i=2;i<=100;i++)
    		{
    			c[i][0]=1;
    			for(int j=1;j<=i;j++)
    			{
    				c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    			}
    		}
    	}
    	
    	void work()
    	{
    		init();
    		scanf("%lld%lld%lld",&n,&k,&m);
    		scanf("%s",a+1);
    		scanf("%s",b+1);
    		for(long long i=1;i<=n;i++)
    		{
    			if(a[i]!=b[i])
    			{
    				cnt++;
    			}
    		}
    		f[0][cnt]=1;
    		for(long long i=1;i<=k;i++)
    		{
    			for(long long j=0;j<=n;j++)
    			{
    				for(long long l=0;l<=min(m,j);l++)
    				{
    					f[i][j-l+m-l]=(f[i][j-l+m-l]+(f[i-1][j]*c[j][l])%mod*c[n-j][m-l]%mod)%mod;
    				}
    			}
    		}
    		printf("%lld",f[k][0]);
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
     } 
    
  • 相关阅读:
    SharedPreferences介绍,用来做数据存储
    android中的回调简单认识
    git的使用
    Android Studio插件美化Android Studio,文艺清新范
    arp欺骗技术
    进程和线程的关系
    Win下常用命令大全
    JavaWeb系列之:Servlet
    JavaWeb系列之:监听器
    JavaWeb系列之:过滤器
  • 原文地址:https://www.cnblogs.com/youth518/p/13653347.html
Copyright © 2011-2022 走看看