ZOJ3690

题目链接:ZOJ3690

题意:有n个人,每个人可以从m个数中选取其中的一个数,而且如果两个相邻的数相同,则这个数不能超过k,问这样的数一共有多少种选择,结果对1e9+7取模。 

 

 

 

分析:考虑以下2个函数

f[n]是第n个人时的答案数

num[n]是第n个人时小于等于k的答案数

不难得出

f[n]=f[n-1]*m-num[n-1]

num[n]=f[n-1]*k-num[n-1]

我们构造如下矩阵:

然后套个矩阵快速幂的板子就好

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=3e5+10;
const int maxn=100;
const ll Mod=1e9+7;
ll tmp[maxn][maxn];
void multi(ll a[][maxn],ll b[][maxn],int n)//n是矩阵大小
{
    int i,j,k;
    memset(tmp,0,sizeof tmp);
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            for(k=1;k<=n;k++)
            {
                tmp[i][j]+=a[i][k]*b[k][j];
                tmp[i][j]%=Mod;
            }

    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
           a[i][j]=tmp[i][j];
}
ll res[maxn][maxn];
void Pow(ll a[][maxn],ll m,int n)// a 是初始矩阵 res是答案数组 m是幂,n是矩阵大小
{
    for(int i=1;i<maxn;i++)
        for(int j=1;j<maxn;j++)
            res[i][j]=(i==j);

    while(m)
    {
        if(m&1) multi(res,a,n);  //res=res*a;
        multi(a,a,n);  //a=a*a
        m>>=1;
    }
}
ll a[maxn][maxn];
int main()
{
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        a[1][1]=m;a[2][2]=-1;
        a[1][2]=-1;a[2][1]=k;
        if(n==0)
        {
            printf("0\n");
            return 0;
        }
        Pow(a,n-1,2);
        ll ans=0;
        ans=(ans+m*res[1][1])%Mod;
        ans=(ans+k*res[1][2])%Mod;
        ans=(ans+Mod)%Mod;
        printf("%lld\n",ans);
    }

    return 0;
}
/*
题目的意思是有n个人和m个数和一个k,现在每个人可以选择一个数,
但是要求如果相邻的两个人选择相同的数,那么这个数要大于k
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值