zoukankan      html  css  js  c++  java
  • 【noip2016十连测round3】T3 涂色游戏 【矩阵快速幂优化dp】

    涂色游戏

    这里写图片描述
    这里写图片描述
    题解:
    推一推公式。
    我们让f[i][j]表示第i列有j种颜色的方案总数,k表示i-1列用了多少种颜色,l表示第i列用了多少种没有在i-1列出现的颜色,G(i,j)表示i个格子涂j种颜色的方案总数。
    f[i][j]=Σ(f[i1][k]C(k,il)C(pk,l)G(n,j))。其中要满足k+l>=q
    G(i,j)怎么求?
    可以得到G(i,j)=jiΣ(g[i][k]c[j][k]),其中k=1..j1。这个式子代表先get到所有的涂法,再减去少于j种颜色的方案总数。
    但是我们发现列数为1e9,怎么办?
    太显然了吧!^ ^直接上矩阵快速幂优化。
    在最后orz orz %%%zjr大佬。老中医保佑!
    代码:

    #include<cstdio>
    #include<cstring>
    #pragma GCC optimize (3)
    typedef long long ll;
    const int N=105;
    const ll mod=998244353;
    int n,m,p,q;
    ll ans,c[N][N],g[N][N];
    ll fast_pow(ll a,int x){
        ll res=1;
        while(x){
            if(x&1){
                res*=a;
                res%=mod;
            }
            x>>=1;
            a*=a;
            a%=mod;
        }
        return res;
    }
    struct matrix{
        ll a[N][N];
        matrix(){
            memset(a,0,sizeof(a));
        }
        matrix operator * (const matrix &b) const{
            matrix c;
            for(int i=1;i<=p;i++){
                for(int j=1;j<=p;j++){
                    for(int k=1;k<=p;k++){
                        c.a[i][j]+=a[i][k]*b.a[k][j];
                        c.a[i][j]%=mod;
                    }
                }
            }
            return c;
        }
    }bg,x;
    int main(){
        scanf("%d%d%d%d",&n,&m,&p,&q);
        if(p<q){
            puts("0");
            return 0;
        }
        for(int i=0;i<=p;i++){
            c[i][0]=c[i][i]=1;
        }
        for(int i=1;i<=p;i++){
            for(int j=1;j<=i;j++){
                c[i][j]=c[i-1][j-1]+c[i-1][j];
                c[i][j]%=mod;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=i&&j<=p;j++){
                g[i][j]=fast_pow(j,i);
                for(int k=1;k<j;k++){
                    g[i][j]-=g[i][k]*c[j][k]%mod;
                    g[i][j]=(g[i][j]%mod+mod)%mod;
                }
            }
        }
        for(int i=1;i<=p&&i<=n;i++){
            for(int j=1;j<=p&&j<=n;j++){
                for(int k=0;k<=i;k++){
                    if(j+k<q){
                        continue;
                    }
                    x.a[j][i]+=c[j][i-k]*c[p-j][k]%mod*g[n][i]%mod;
                    x.a[j][i]%=mod;
                }
            }
        }
        for(int i=1;i<=p;i++){
            bg.a[1][i]=c[p][i]*g[n][i]%mod;
        }
        m--;
        while(m){
            if(m&1){
                bg=bg*x;
            }
            m>>=1;
            x=x*x;
        }
        for(int i=1;i<=p;i++){
            ans+=bg.a[1][i];
            ans%=mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    【MM系列】SAP库龄报表逻辑理解
    【MM系列】SAP技巧之更改布局
    【MM系列】SAP里批量设置采购信息记录删除标记
    《跃迁-从技术到管理的硅谷路径》读书笔记
    Java安全编码标准
    web安全/渗透测试--1--web安全原则
    使用spring validation完成数据后端校验
    9 个Java 异常处理的规则
    程序员必看:给你一份详细的Spring Boot知识清单
    Java架构技术知识点梳理
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476880.html
Copyright © 2011-2022 走看看