zoukankan      html  css  js  c++  java
  • P2182 翻硬币 (dp)

    P2182 翻硬币

    分析:

    60分的状压很好想:定义dp[ i ][ sta ]为翻了i次,状态为sta的方案数,枚举状态转移即可。

    但n的范围是100。

    遇到这种情况肯定不能状压了,一般是把记录状态换成记录其他东西。

    比如说中国象棋这道题,就是将记录状态转换成记录个数。

    这道题也是一样,记录初始状态与终止状态不同的个数。

    枚举个数转移即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 105
    #define ri register int
    #define ll long long
    const ll mod = 1e9+7;
    int n,m,k,d=0;
    ll dp[N][N],fac[N],invfac[N];
    char a[N],b[N];
    ll quick_pow(ll a,ll k)
    {
        ll ans=1;
        while(k) { if(k&1) ans=ans*a %mod; a=a*a %mod; k>>=1; }
        return ans;
    }
    void init(int n)
    {
        fac[0]=1;
        for(ri i=1;i<=n;++i) fac[i]=fac[i-1]*i %mod;
        invfac[n]=quick_pow(fac[n],mod-2);
        for(ri i=n;i>=1;--i) invfac[i-1]=invfac[i]*i %mod;
    }
    ll C(int n,int m)
    {
        if(n<m) return 0;
        return fac[n]*invfac[n-m] %mod *invfac[m] %mod;
    }
    int main()
    {
        scanf("%d%d%d",&n,&k,&m);
        init(n);
        scanf("%s%s",a+1,b+1);
        for(ri i=1;i<=n;++i) d+=(a[i]!=b[i]);
        dp[0][d]=1;
        for(ri i=1;i<=k;++i)
         for(ri j=0;j<=n;++j)//j个不同 
          for(ri r=0;r<=min(j,m);++r)//枚举的是翻了r个是j个不同里面的 
           if(j+m-2*r>=0 && j+m-2*r<=n)
            //翻了r个不同的,把它变成相同的,此时不同的还有:j-r个。
            //还剩 m-r个翻到了原来相同的,变成了m-r个不同的,所以新的不同的个数是:j+m-2*r 
            dp[i][j+m-2*r]=( dp[i][j+m-2*r] + dp[i-1][j]*C(j,r) %mod *C(n-j,m-r) %mod) %mod;
            //组合数:1.j个不同的选r个翻。2.n-j个相同的选m-r个翻 
        printf("%lld
    ",dp[k][0]);
    }
    View Code
  • 相关阅读:
    操作系统的运行机制
    操作系统的目标和功能
    操作系统的特征
    操作系统的基本概念
    error: a label can only be part of a statement and a declaration is not a statement
    克隆git仓库中的一个分支
    ubuntu下update-alternatives命令的使用
    堆排序
    合并排序
    递归算法的一些规则
  • 原文地址:https://www.cnblogs.com/mowanying/p/11808858.html
Copyright © 2011-2022 走看看