Educational Codeforces Round 60 (Rated for Div. 2) D - Magic Gems (dp+矩阵快速幂)

Description:

有一个大小为n的01数列,规定每次0要么不出现要么连续m的倍数个0出现在一块区域,问有多少种这样不同的序列

Input:

n,m

Output:

ans

Analysis:

用dp(i)表示总共有i个元素共有多少个这样的序列。可以根据当前考虑的序列最后是1还是m个连续的0,得到状态转移方程为dp[i]=d[i-1]+dp[i-m]

这题的n很大,由于状态转移方程是线性的,可以用快速矩阵幂求解。这里有个关于快速矩阵幂求这种dp的文章挺好的

http://fusharblog.com/solving-linear-recurrence-for-programming-contest/

#define _CRT_SECURE_NO_WARNINGS  
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<unordered_set>
#include<ctime>
#include<cstring>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef  long long LL;
const int INF = 1 << 30;
const int maxn = 105;
const int MOD = 1e9+7;
const double eps = 1e-6;
const double pi = acos(-1);

LL n, m;

LL T[maxn][maxn];
LL f[maxn];

void Mul_mat(LL fin[][maxn], LL b[][maxn]) {
	LL ans[maxn][maxn];
	_for(i, 0, m)
		_for(j, 0, m)
		ans[i][j] = 0;
	_for(i,0,m)
		_for(j,0,m)
		_for(k, 0, m) {
		ans[i][j] = (ans[i][j] + fin[i][k] * b[k][j]) % MOD;
	}
	_for(i, 0, m)
		_for(j, 0, m)
		 fin[i][j] = ans[i][j];
}

void Pow_mat(LL n,LL fin[][maxn], LL b[][maxn]) {
	LL ans[maxn][maxn];
	_for(i, 0, m)
		_for(j, 0, m) {
		if(i!=j)ans[i][j] = 0;
		else ans[i][j] = 1;
	}
	while (n) {
		if (n & 1) Mul_mat(ans,b);
		Mul_mat(b, b);
		n >>= 1;
	}
	memcpy(fin, ans, sizeof(ans));
}

int main()
{
	//freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);
	
	ios_base::sync_with_stdio(0);//用这个
	cin.tie(0);                    //就能防止cin超时orz

	while (cin >> n >> m) {

		if (n < m) {
			cout << 1 << endl;
			continue;
		}

		memset(T, 0, sizeof(T));
		_for(i, 0, m - 1)
			T[i][i + 1] = 1;
		T[m - 1][0] = T[m - 1][m - 1] = 1;

		
		LL f[maxn]; 
		_for(i, 0, m - 1)f[i] = 1;
		f[m - 1] = 2;
		LL tmp[maxn][maxn];
		memset(tmp, 0, sizeof(tmp));
		Pow_mat(n - 1, tmp, T);
		LL ans = 0;
		_for(i, 0, m) {
			ans = (ans + tmp[0][i] * f[i]) % MOD;
		}
		cout << ans << endl;
	}

	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/87867300