【刷题】【dp】【矩阵加速】花园

不看数据范围,本题和动物园特别像,

小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15)。他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<=M<=5,M<=N)个花圃中有不超过K(1<=K<M)个C形的花圃,其余花圃均为P形的花圃。

例如,N=10,M=5,K=3。则

CCPCPPPPCC 是一种不符合规则的花圃;

CCPPPPCPCP 是一种符合规则的花圃。

请帮小L求出符合规则的花园种数Mod 1000000007

由于请您编写一个程序解决此题。

40%的数据中,N<=20;

60%的数据中,M=2;

80%的数据中,N<=10^5。

扫描二维码关注公众号,回复: 7562003 查看本文章

100%的数据中,N<=10^15。

就是最后两个点不能过,

不过我们可以把 i -> j 状态存在矩阵中,做出一张floyd表,

然后logn矩阵加速

#include<cstdio>
#include<cstdlib>
#define ll long long 
using namespace std;
ll n,mod=1000000007;
int m,mm;

int tot,st[35]; 
struct node
{
    ll d[35][35]; 
}relate,ans,t; 

void mul(node &a ,node b )
{
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            for(int k=1;k<=tot;k++)
                t.d[i][j]=(t.d[i][j]+a.d[i][k]*b.d[k][j]%mod)%mod;
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            a.d[i][j]=t.d[i][j],t.d[i][j]=0;
}

ll sum;
int main()
{
    scanf("%lld%d%d",&n,&m,&mm);
    int mx=(1<<m)-1;
    for(int i=0;i<=mx;i++) 
    {
        int x=i,cnt=0;
        while(x)
            if(x&1) cnt++,x>>=1;
            else x>>=1;
        if(cnt<=mm)
            st[++tot]=i;
    }
    
    int sd1=mx^(1<<m-1),sd2=mx^1;
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            if( (st[i]&sd1) == ((st[j]&sd2)>>1) )
                relate.d[i][j]=1;
        
    ll a=1;
    for(int i=1;i<=tot;i++)
            ans.d[i][i]=1;
    while(a<=n)
    {
        if(n&a ) 
            mul(ans,relate);
        a<<=1,mul(relate,relate);
    }
    for(int i=1;i<=tot;i++)
        sum=(sum+ans.d[i][i])%mod;
    printf("%lld\n",sum);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/xwww666666/p/11730681.html