【NOIP2018模拟赛2018.10.23】木门道伏击战

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41709770/article/details/83315615

题目

木门道伏击战(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;
}

猜你喜欢

转载自blog.csdn.net/qq_41709770/article/details/83315615
今日推荐