zoukankan      html  css  js  c++  java
  • [题解]luogu_P5004跳房子2(矩乘递推

    一开始算出来了每个点的贡献,最后还要O(n)求和,而且递推式还带求和号(而且竟然还是倒着推的,不可矩乘优化

    如果正着写:$g[i]= sum_{j=1}^{i-m-1}g[j]$,i每后移一个只增加一个数,去掉求和号:$g[i]=g[i-1]+g[i-m-1]$

    答案为g[i]的和+1(全空的情况

    然而答案的递推式竟然是:$f[i]=f[i-1]+f[max(i-m-1,0)](f[0]=1)$,(特判$f[1]=2$,

    几乎一样啊,只有它会从0转移不同....其实也好理解,如果这个点不染色那么和前面一样$f[i-1]$,如果染色那么前面m个都不会被染色,答案加上一个$f[i-m-1]$,如果$i<=m+1$那么染色方案只会加1,因为只能选一个点染(也就是这段$f[i]=i+1$

    这样矩乘转移矩阵就显然了

    不开longlong见祖宗

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int mod=1e9+7;
    ll n,m;
    struct mat{
        ll a[20][20];
        void clear(){
            memset(a,0,sizeof(a));
        }
        mat operator *(const mat&t)const{
            mat ans;ans.clear();
            for(int i=1;i<=m+1;i++)
            for(int j=1;j<=m+1;j++)
            for(int k=1;k<=m+1;k++)
            (ans.a[i][j]+=a[i][k]*t.a[k][j])%=mod;
            return ans;
        }
    }ans,p;
    mat operator ^(mat x,ll b){
        mat ans;ans.clear();for(int i=1;i<=m+1;i++)ans.a[i][i]=1;
        while(b){
            if(b&1)ans=ans*x;
            x=x*x;
            b>>=1;
        }
        return ans;
    }
    int main(){
        scanf("%lld%d",&n,&m);
        for(int i=1;i<=m+1;i++)ans.a[1][m+2-i]=i+1;
        p.a[1][1]=1;
        p.a[m+1][1]=1;
        for(int i=1;i<=m;i++)p.a[i][i+1]=1;
        if(n<=m+1){
            printf("%d",ans.a[1][m+2-n]);return 0;
        }
        p=p^(n-m-1);ans=ans*p;
        printf("%lld",ans.a[1][1]);
    }
  • 相关阅读:
    PHP学习(二)
    PHP学习(一)
    JQuery学习小结
    Java学习(七)标准标签库JSTL
    Java学习(六)servlet 的引入
    Java学习(五)例题
    java学习(四)代码的设计
    Java学习(三)JSP学习1
    采用prometheus 监控mysql
    commonjs, nodejs, npm, browserify, watchify
  • 原文地址:https://www.cnblogs.com/superminivan/p/11598350.html
Copyright © 2011-2022 走看看