[JZOJ5335] 早苗

来源:互联网 发布:网络专业课程 编辑:程序博客网 时间:2024/06/10 09:56

题目描述

这里写图片描述
这里写图片描述

分析

早上做题拉肚子…死都想不出来怎么做。
我们首先注意到不同的神风没有什么不同,就是说,我们只要知道他们是不同,而没有必要知道他们到底是哪几种。
那么设f[i][j]表示到第i天,第i-j+1~i天的神风各不相同(i-j天为这几天出现过的某个点),只要j<m,构造出来的方案一定是合法的嘛,然后转移比较容易,因为本质差不多,考虑第i+1天的神风是什么,如果和之前都不同,f[i+1][j+1]+=(mj)f[i][j],然后和前j天某一天一样的神风只有一种,那么f[i+1][k]+=f[i][j],k<=j。
用矩阵乘法优化一下就行了。

代码

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<set> using namespace std;typedef long long ll;typedef double db;#define fo(i,j,k) for(i=j;i<=k;i++)#define fd(i,j,k) for(i=j;i>=k;i--)const int N=105,mo=1e9+7,mx=1e9;int a[N][N],b[N][N],c[N][N],f[N],g[N],ans,i,j,k,m;ll n;void ksm(ll x){    fo(i,0,m) a[i][i]=1;    while (x)    {        if (x&1)        {            fo(i,0,m) fo(j,0,m) c[i][j]=0;            fo(i,0,m) fo(j,0,m) fo(k,0,m) c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%mo;            fo(i,0,m) fo(j,0,m) a[i][j]=c[i][j];        }        x>>=1;        fo(i,0,m) fo(j,0,m) c[i][j]=0;        fo(i,0,m) fo(j,0,m) fo(k,0,m) c[i][j]=(c[i][j]+1ll*b[i][k]*b[k][j])%mo;        fo(i,0,m) fo(j,0,m) b[i][j]=c[i][j];    }}int main(){    freopen("t2.in","r",stdin);//  freopen("t2.out","w",stdout);    scanf("%lld %d\n",&n,&m);    fo(i,0,m-2) b[i][i+1]=m-i;    fo(i,1,m-1) fo(j,1,i) b[i][j]=1;    f[0]=1;    ksm(n);    fo(i,0,m-1)     {        fo(j,0,m-1) g[i]=(g[i]+1ll*a[j][i]*f[j])%mo;        ans=(ans+g[i])%mo;    }    printf("%d\n",ans);}