zoukankan      html  css  js  c++  java
  • dtoj3226荒芜废墟(ruins)

    荒芜废墟(ruins)

     Ori来到了荒芜废墟,荒芜废墟可以看成一条数轴。Ori一开始在 $ 0 $ ,每一次可以往右跳 $ leq k $ 的步。但有些位置设置了激光,这些位置Ori是无法到达的,一共有 $ m $ 种激光,每一种激光有一个特征值 $ t_i $ 表示这种激光会出现在 $ t_i $ 以及 $ t_i $ 的倍数的位置上。Ori想要知道从 $ 0 $ 走到 $ n $ 有多少种走法。


    对于100%的数据, $ nleq10^9 $ , $ mleq3,kleq50 $ ,保证ti,k可以写成 $ 2^a*3^b $ 的形式,其中 $ a,bleq5 $


     Sol

    n是1e9,我们考虑矩乘来转移。

    注意到 $ 2^a*3^b leq 3125$ 

    也就是说ti和k的lcm最多3125,记为T

    前k步的转移是有限制的,不能从转i<0转,需要特殊处理

    处理完我们就T步T步的转移,每T步的转移都是相同的。

    最后一段也暴力转移即可。

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define mod 1000000007
    using namespace std;
    int n,m,k,t[4],T; 
    ll f[55],F[8005],a[8500][55];
    struct node{
        ll v[52][52];
    }p,ans;
    node ch(node a,node b){
        node c;
        for(int i=0;i<k;i++)
        for(int j=0;j<k;j++){
            c.v[i][j]=0;
            for(int x=0;x<k;x++){
                c.v[i][j]=(c.v[i][j]+a.v[i][x]*b.v[x][j]%mod)%mod;
            }
        }
        return c;
    }
    int main(){
    
        cin>>n>>m>>k;T=k;
        for(int i=1;i<=m;i++){
            scanf("%d",&t[i]);
            T=T*t[i]/__gcd(T,t[i]);
        }
        f[0]=1;a[0][0]=1;
        for(int i=1;i<=k-1;i++){
            a[i][i]=1;
            for(int j=i-1;j>=0;j--){
                f[i]=(f[i]+f[j])%mod;
            }
            for(int x=1;x<=m;x++)if(i%t[x]==0)f[i]=0;
        }
        for(int i=k;i<T+k;i++){
            for(int j=i-1;j>=i-k;j--){
                int fl=0;for(int x=1;x<=m;x++)if(j%t[x]==0)fl=1;
                if(fl&&j)continue;
                for(int x=0;x<k;x++){
                    a[i][x]=(a[i][x]+a[j][x])%mod;
                }
            }
            for(int j=1;j<=m;j++){
                if(i%t[j]==0)for(int x=0;x<k;x++)a[i][x]=0;
            }
        }
        for(int i=T;i<T+k;i++){
            for(int j=0;j<k;j++)p.v[j][i-T]=a[i][j];
            ans.v[i-T][i-T]=1;
        }
        int num=n/T;n%=T;
        while(num){
            if(num&1)ans=ch(ans,p);
            p=ch(p,p);num>>=1;
        }
        for(int i=0;i<k;i++){
            for(int j=0;j<k;j++){
                F[i]=(F[i]+ans.v[j][i]*f[j]%mod)%mod;
            }
        }
        for(int i=k;i<=n;i++){
            for(int j=i-1;j>=i-k;j--){
                F[i]=(F[i]+F[j])%mod;
            }
            for(int x=1;x<=m;x++)if(i%t[x]==0)F[i]=0;
        }
        cout<<F[n]<<endl;
        
        return 0;
    }
  • 相关阅读:
    Elasticsearch 支持拼音自动补全
    laravel自动补全链接
    laravel的服务容器(药箱)、服务提供者(小盒子)、Facades(更方便用药),方便大家透彻理解
    php static静态属性和静态方法
    php面向对象的构造方法与析构方法
    MySQL事务-ROLLBACK,COMMIT用法详解
    php 事务处理transaction
    Python:初步学习Python
    iOS:自己写的一个星级评价的小Demo
    iOS:枚举enum的使用
  • 原文地址:https://www.cnblogs.com/liankewei/p/12323088.html
Copyright © 2011-2022 走看看