zoukankan      html  css  js  c++  java
  • UVA 12297 Super Poker

    UVA_12297

        在研究了好一阵子标程之后终于把标程的解体思路弄懂了,其实关键之处就在于标程给出的递推式:f(n, k) = f(n-k, k) + f(n-k, k-1) * 4 + f(n-k, k-2) * 6 + f(n-k, k-3) * 4 + f(n-k, k-4)。

        这里f(n, k)表示用k张牌组成和为N的方案数,在递推的时候考虑一共有多少张1。①考虑有0张1:这时就相当于用k张没有任何限制的牌组成和为n-k,然后将每张牌的点数+1,这样自然就没有1了,这部分的方案数是f(n-k, k);②考虑有1张1:这时就相当于用k-1张没有任何限制的牌组成和为n-k,然后将每张牌的点数+1,这样也就没有1了,这时总和是n-1,再从4张1种任选一张1就可以使总和为n,这样就恰好用了k张牌,而且k张牌中只有1个1,这部分的方案数是f(n-k, k-1) * C(4,1),也就是f(n-k, k-1) * 4;③考虑有2张1:……(剩下的情况类似,就不再赘述了)。

        有了这个递推式后就会发现是可以用矩阵加速运算了,由于那个矩阵确实有点大,就不再贴图了,在纸上画一画之后还是不难构造出来的。

        此外还有一种解法,但是始终没看懂什么意思,如果各位仁兄看懂了的话还望教小弟一下,链接:http://hi.baidu.com/wjbzbmr/blog/item/88c8b93aed71fb38b9998f45.html

     

    View Code (标程)
    #include <set>
    #include <map>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long i64;
    
    const int MOD = 1000000009;
    const int NN = 256;
    
    // recurrence: f(n, k) = f(n-k, k) + f(n-k, k-1) * 4 + f(n-k, k-2) * 6 + f(n-k, k-3) * 4 + f(n-k, k-4)
    
    int n, k, N, pos[18][18];;
    int base[NN][NN], res[NN][NN], temp[NN][NN];
    
    int multiply( int A[NN][NN], int B[NN][NN], int C[NN][NN] ) {
        for( int i = 0; i < N; i++ ) for( int j = 0; j < N; j++ ) {
            temp[i][j] = 0;
            for( int k = 0; k < N; k++ ) if( A[i][k] && B[k][j] ) temp[i][j] = ( temp[i][j] + A[i][k] * (i64)B[k][j] ) % MOD;
        }
        for( int i = 0; i < N; i++ ) for( int j = 0; j < N; j++ ) C[i][j] = temp[i][j];
    }
    
    void buildBase() {
        for( int i = 0; i < N; i++ ) {
            for( int j = 0; j < N; j++ ) base[i][j] = res[i][j] = 0;
            res[i][i] = 1;
        }
        // build base
        int x = 0;
        for( int j = k; j >= 1; j-- ) for( int i = k + 1; i > 1; i-- ) {
            if( pos[i][j] == -1 ) {
                int p = i - j, q = j;
                if( p >= 1 ) {
                    assert( pos[p][q] > -1 ); base[x][ pos[p][q] ] = 1;
                    q--;
                    if( q > 0 ) {
                        assert( pos[p][q] > -1 ); base[x][ pos[p][q] ] = 4;
                        q--;
                        if( q > 0 ) {
                            assert( pos[p][q] > -1 ); base[x][ pos[p][q] ] = 6;
                            q--;
                            if( q > 0 ) {
                                assert( pos[p][q] > -1 ); base[x][ pos[p][q] ] = 4;
                                q--;
                                if( q > 0 ) {
                                    assert( pos[p][q] > -1 ); base[x][ pos[p][q] ] = 1;
                                }
                            }
                        }
                    }
                }
            }
            else base[x][ pos[i][j] ] = 1;
            x++;
        }
    }
    
    int solve() {
        int dp[20][17] = {0};
    
        dp[0][0] = 1;
        for( int i = 1; i < 20; i++ ) {
            for( int j = 1; j <= k; j++ ) {
                int p = i - j, q = j;
                if( p >= 0 && q >= 0 ) dp[i][j] = (dp[i][j] + dp[p][q]) % MOD;
                q--; if( p >= 0 && q >= 0 ) dp[i][j] = (dp[i][j] + 4 * (i64) dp[p][q]) % MOD;
                q--; if( p >= 0 && q >= 0 ) dp[i][j] = (dp[i][j] + 6 * (i64) dp[p][q]) % MOD;
                q--; if( p >= 0 && q >= 0 ) dp[i][j] = (dp[i][j] + 4 * (i64) dp[p][q]) % MOD;
                q--; if( p >= 0 && q >= 0 ) dp[i][j] = (dp[i][j] + dp[p][q]) % MOD;
            }
        }
        if( n < 20 ) {
            int r = 0;
            for( int i = 1; i <= k; i++ ) r = ( r + dp[n][i] ) % MOD;
            return r;
        }
        int f[NN] = {0}, f1[NN] = {0};
        N = 0;
        memset( pos, -1, sizeof(pos) );
        for( int i = k; i >= 1; i-- ) for( int j = k; j >= 1; j-- ) {
            f[N] = dp[j][i];
            pos[j][i] = N++;
        }
    
        buildBase();
    
        int p = n - k;
    
        while( p ) {
            if( p & 1 ) multiply( res, base, res );
            multiply( base, base, base );
            p >>= 1;
        }
    
        for( int i = 0; i < N; i++ ) for( int k = 0; k < N; k++ ) if( f[k] && res[i][k] ) f1[i] = (f1[i] + res[i][k] * (i64)f[k]) % MOD;
    
        int r = 0;
        for( int i = 0; i < N; i += k ) r = ( r + f1[i] ) % MOD;
        return r;
    }
    
    int main() {
        double cl = clock();
    
        while( scanf("%d %d", &n, &k) == 2 && n ) {
            printf("%d\n", solve());
        }
    
        cl = clock() - cl;
        fprintf(stderr, "Total Execution Time = %lf seconds\n", cl / CLOCKS_PER_SEC);
    
        return 0;
    }
    View Code (My code)
    #include<stdio.h>
    #include<string.h>
    #define MAXD 120
    #define MOD 1000000009
    typedef long long LL;
    int temp[MAXD][MAXD], f[15][15], N, K;
    int n;
    const int d[] = {1, 4, 6, 4, 1};
    struct matrix
    {
        int a[MAXD][MAXD];
        void init(int x)
        {
            for(int i = 0; i < n; i ++)
                for(int j = 0; j < n; j ++)
                    a[i][j] = x;
        }
        matrix operator * (const matrix &t) const
        {
            matrix ans;
            ans.init(0);
            for(int i = 0; i < n; i ++)
                for(int k = 0; k < n; k ++)
                    if(a[i][k])
                    {
                        for(int j = 0; j < n; j ++)
                            if(t.a[k][j])
                                ans.a[i][j] = (ans.a[i][j] + (LL)a[i][k] * t.a[k][j]) % MOD;
                    }
            
            return ans;
        }
    }mat, unit;
    void prepare()
    {
        memset(f[0], 0, sizeof(f[0]));
        f[0][0] = 1;
        for(int i = 1; i <= 10; i ++)
            for(int j = 1; j <= 10; j ++)
            {
                f[i][j] = 0;
                if(i >= j)
                {
                    for(int k = 0; k < 5 && j - k >= 0; k ++)
                        f[i][j] = (f[i][j] + (LL)d[k] * f[i - j][j - k]) % MOD;
                }
            }
    }
    void build()
    {
        n = K * (K + 1);
        mat.init(0);
        for(int i = 0; i < K; i ++)
            for(int j = 0; j <= K; j ++)
                mat.a[i * (K + 1) + j][0] = f[K - 1 - i][j];
        
        unit.init(0);
        for(int j = 1; j <= K; j ++)
        {
            for(int k = 0; k < 5 && j - k >= 0; k ++)
                unit.a[j][(j - 1) * (K + 1) + j - k] = d[k];
        }
        for(int i = 1; i < K; i ++)
            for(int j = 0; j <= K; j ++)
                unit.a[i * (K + 1) + j][(i - 1) * (K + 1) + j] = 1;    
    }
    void powmod(int n)
    {
        while(n)
        {
            if(n & 1)
                mat = unit * mat;
            n >>= 1, unit = unit * unit;    
        }
    }
    void solve()
    {
        if(N <= 10)
        {
            int ans = 0;
            for(int i = 1; i <= K; i ++)
                ans = (ans + f[N][i]) % MOD;
            printf("%d\n", ans);
            return ;
        }
        build();
        powmod(N - K + 1);
        int ans = 0;
        for(int i = 1; i <= K; i ++)
            ans = (ans + mat.a[i][0]) % MOD;
        printf("%d\n", ans);
    }
    int main()
    {
        prepare();
        while(scanf("%d%d", &N, &K) == 2, N || K)
            solve();
        return 0;    
    }
  • 相关阅读:
    2018-2019-2 20189212 《网络攻防技术》第一周作业
    2017、5、4
    Pyinstaller 打包exe 报错 "failed to execute script XXX"的一种解决方案
    解决 Onenote 默认全角输入的一种解决办法(输入法已经设置为默认半角)
    OneDrive一直后台占用CPU的一种解决办法
    etimer
    简单三层BP神经网络学习算法的推导
    win10无法设置移动热点的一种解决办法
    如何恢复误删的OneNote页面
    安装mysql遇到的坑--->Can't connect to MySQL server on 'localhost' (10061)
  • 原文地址:https://www.cnblogs.com/staginner/p/2622102.html
Copyright © 2011-2022 走看看