码迷,mamicode.com
首页 > 其他好文 > 详细

hdu3658(矩阵快速幂)

时间:2015-06-01 22:44:14      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

题意:

给出一个序列的长度;

这个序列只能有A-Z,a-z;

而且要求相邻的字母asiic 码差值小于等于32;而且必须有一个是等于32的;

问有种排列;


思路:

构造一个52  * 52的矩阵,把每个字母后面能跟哪些标为1;

然后矩阵快速幂;

然后再把差值为32的标志为0,在算一次(这样算出来的就是肯定不会有差值等于32的)

两次结果相减;


#include<cstdio>
#include<cstring>
#define ll long long
struct mat {
	ll g[60][60];
}res, ori;

const ll MOD = 1e9 + 7;
ll n;
void init() {
	memset(ori.g ,0, sizeof(ori.g));
	memset(res.g ,0, sizeof(res.g));
	for(int i = 0; i < 26; i++) {
		for(int j = 0; j <= i + 26; j++) {
			ori.g[j][i] = 1;
		}
	}
	for(int i = 26; i < 52; i++) {
		for(int j = 51; j >= i - 26 ; j--) {
			ori.g[j][i] = 1;
		}
	}
	for(int i = 0; i < 52; i++) {
		res.g[0][i] = 1;
	}
}
mat mul(mat a, mat b) {
	mat tmp;
	memset(tmp.g, 0, sizeof(tmp.g));
	for(int i = 0; i < 52; i++) {
		for(int j = 0; j < 52; j++) {
			for(int k = 0; k < 52; k++) {
				tmp.g[i][j] = (tmp.g[i][j] + a.g[i][k] * b.g[k][j])% MOD;
			}
		}
	}
	return tmp;
}
ll cul(ll k) {
	while(k) {
		if(k & 1)
			res = mul(res, ori);
		k >>= 1;
		ori = mul(ori, ori);
	}
	ll ans = 0;
	for(int i = 0; i < 52; i++) {
		ans = (ans + res.g[0][i]) % MOD;
	}
	return ans;
}
int main() {
	int t;
	scanf("%d",&t);
	while(t--) {
		scanf("%lld",&n);
		init();
		ll k1 = cul(n - 1);
		init();
		for(int i = 0; i < 26; i++) {
			ori.g[i + 26][i] = 0;
		}
		for(int i = 26; i < 52; i++) {
			ori.g[i - 26][i] = 0;
		}
		ll k2 = cul(n - 1);
		printf("%lld\n",(k1  + MOD- k2) % MOD);
	}
}


hdu3658(矩阵快速幂)

标签:

原文地址:http://blog.csdn.net/yeyeyeguoguo/article/details/46315641

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!