题目
木门道伏击战(intercept)
【题目背景】
建兴九年(231 年), 诸葛亮率蜀军四出祁山。 司马懿料到蜀军粮草不济,坚守
不出,又命人在成都散布诸葛亮欲谋反的谣言。刘禅听信谣言,下旨命诸葛亮退
兵。在退兵时,魏军决定追击,诸葛亮早有防备,在木门道伏击射杀张郃。
【题目描述】 小 W 在《三国演义》中读到四出祁山,对此非常感兴趣,在思考这场战役时 他想出了一个问题。 小 W 认为蜀军共有 N 处伏击地点,可以把这 N 个伏击地点从 1 到 N 进行标 号,且蜀军恰好有 M 个兵种。 由于伏击需要保证军队可以方便地调度,所以不 存在连续 M 个伏击地点埋伏了 M 个不同的兵种。小 W 想知道所有不同的埋伏 方案数对 1e9+7 取模。
【输入格式】
从文件 intercept.in 中读入数据。
一行一个数 N。
输出格式】
输出到文件 intercept.out 中。
一行一个数,表示结果对 1e9+7 取模的结果。
【样例输入 1】
3 3
【样例输出 1】
21
【数据范围】 对于 8%的数据, m=2
对于另 16%的数据, n<=10,m<=4
对于 48%的数据, n<=100000,m<=10
对于 80%的数据, n<=100000,2<=m<=100
对于 100%的数据, 2<=m<=100,m<=n<=10^16
题解
–是dp
f[i][j]:前i个位置,末尾最长不相同序列长度为j的方案数
可 以 乘 上(m-j)之 后 转 移 到f[i+1][j+1],
也 可 以 转 移 到f[i+1][k](1<=k<=j)。
由于第二维只到100,并且转移的系数是固定的,所以可以用矩阵乘法进行优化。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=105;
const int mod=1e9+7;
long long n,m;
struct hehe{
long long f[MAXN][MAXN];
}a,b;
hehe mul(hehe a,hehe b){
hehe c;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++){
c.f[i][j]=0;
for(int k=1;k<=m;k++)
c.f[i][j]=(c.f[i][j]+a.f[i][k]*b.f[k][j]%mod)%mod;
}
return c;
}
long long Pow(hehe a,long long b){
hehe ans;
for(int i=1;i<=m;i++)
ans.f[i][i]=1;
while(b){
if(b&1)
ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
long long sum=0;
for(int i=1;i<=m;i++)
sum=(sum+ans.f[i][1])%mod;
return sum;
}
int main(){
// freopen("intercept.in","r",stdin);
// freopen("intercept.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++){
if(i-1==j)
a.f[i][j]=m-(j-1);
else if(i==1)
a.f[i][j]=0;
else if(i<=j)
a.f[i][j]=1;
}
cout<<Pow(a,n);
return 0;
}