• 翻硬币


    题目描述

    小Z离开家的时候忘记带走了钱包,掉下的硬币在桌子上排成了一列。正在等着哥哥回来的小D坐在桌子旁边,无聊地翻着桌子上的硬币。

    出于某种爱好,小D一次一定会同时翻转 M 枚硬币。由于小D是一个爱动脑的小学生,这样进行了若干次之后她很快想到了一个问题:有多少种方法能够在 K 次翻转后把硬币由原来的状态变成现在这样呢?

    因为小D是个好学的小学生,她只需要你告诉她方案数对 1000000007 取模的值以方便她进行验算就可以了。

    输入输出格式

    输入格式:

    第一行,包含三个字符 N,K,M ,表示硬币的数量,翻转的次数和每次翻转的硬币数量。

    第 2~3 行,包含 N 个字母,表示硬币在一开始的状态和最终要变成的状态。1 表示正面而 0 表示背面。

    输出格式:

    一行包含一个整数,表示方案数对 1000000007 取模的值。

    输入输出样例

    输入样例#1:

    3 2 1
    100
    001

    输出样例#1:

    2

    说明

    【样例解释】

    100→101→001

    100→000→001

    【数据规模】

    对于 30% 的数据,N ≤ 4,0 ≤ K ≤ 5;

    对于 60% 的数据,N ≤ 10;

    对于 100% 的数据,1 ≤ N ≤ 100,0 ≤ K ≤ 100,0 ≤ M ≤ N 。


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define int long long 
    const int M = 105 ;
    const int mod = 1e9 + 7 ;
    using namespace std ;
    inline int read() {
        char c = getchar() ; int x = 0 , w = 1 ;
        while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
        while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
        return x*w ;
    }
    
    int n , T , m ;
    int fir[M] , sec[M] ;
    int c[M][M] , f[M][M] ;
    int tot ;
    // f[i][j] 表示第i轮结束后有j个是不符合的
    # undef int
    int main() {
    # define int long long
        n = read() ; T = read() ; m = read() ;
        char s[105] ;  scanf("%s",s + 1) ;
        for(int i = 1 ; i <= n ; i ++) fir[i] = s[i] - '0' ;
        scanf("%s",s + 1) ;
        for(int i = 1 ; i <= n ; i ++) sec[i] = s[i] - '0' ;
        c[0][0] = 1 ;
        for(int i = 1 ; i <= n ; i ++) {
            c[i][0] = 1 ;
            for(int j = 1 ; j <= i ; j ++)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod ;
        }
        for(int i = 1 ; i <= n ; i ++)
            if(fir[i] != sec[i])
                ++tot ;
        f[0][tot] = 1 ;
        for(int i = 1 ; i <= T ; i ++)
            for(int j = 0 ; j <= n ; j ++) 
            // 当前状态有多少个与原数列不同的硬币 
                for(int k = 0 ; k <= min(j , m) ; k ++) { 
                // 翻转了m个硬币,翻转的硬币中有多少是由不合法翻成合法的 
                // 所以减少了k个不合法的,增加了m-k个不合法的
                    if(m - k + j - k >= 0 && m - k + j - k <= n)
                    	// 进行了这次反转后还剩下多少不合法的硬币个数
                        f[i][m - k + j - k] = (f[i][m - k + j - k] % mod + ((f[i - 1][j] * ((c[n - j][m - k] * c[j][k]) % mod)) % mod)) % mod ; 
                        //  c[n - j][m - k] :  表示从n-j个合法的硬币中翻转m-k个变成不合法的方案数 
    					//  c[j][k]  : 表示从j个不合法的硬币中翻转k个变成合法的方案数 
                }	
        cout << f[T][0] << endl ;
        return 0 ;
    }
    
  • 相关阅读:
    ibatis.net:惯用法
    ibatis.net:在VS中支持xml智能提示
    设计原则:色彩
    编码原则:“防御式编程”再次让我快乐
    错误:update 忘了加 where
    .NET:不要使用扩展方法扩展Object对象。
    错误:不小心的VS重命名
    技术人生:如何更有效率的切换上下文?
    Logstash filter 插件之 grok
    轻松测试 logstash 的配置文件
  • 原文地址:https://www.cnblogs.com/beretty/p/9670331.html
Copyright © 2020-2023  润新知