HDU_3658
可以用f[i][j]表示第i个字符为j时满足要求(有至少一对相邻的字符的ASC码值之差是32)的合法(任意一对相邻的字符的ASC码值之差都不超过32)字符串个数,g[i][j]表示第i个字符为j时不满足要求但合法的字符串个数。找到递推关系之后构造矩阵并用二分矩阵的方法求解即可。
#include<stdio.h> #include<string.h> #define MAXD 110 #define D 1000000007 int N; struct Matrix { int a[MAXD][MAXD]; Matrix() { memset(a, 0, sizeof(a)); } }; Matrix multiply(Matrix &x, Matrix &y) { int i, j, k; Matrix z; for(k = 0; k < 104; k ++) for(i = 0; i < 104; i ++) if(x.a[i][k]) { for(j = 0; j < 104; j ++) if(y.a[k][j]) z.a[i][j] = (z.a[i][j] + (long long)x.a[i][k] * y.a[k][j]) % D; } return z; } void powmod(Matrix &unit, Matrix &mat, int n) { while(n) { if(n & 1) unit = multiply(mat, unit); n >>= 1; mat = multiply(mat, mat); } } void solve() { int i, j; Matrix mat, unit; long long ans = 0; for(i = 52; i < 104; i ++) unit.a[i][0] = 1; for(i = 0; i < 26; i ++) { for(j = 0; j <= 26 + i; j ++) mat.a[i][j] = 1; mat.a[i][i + 78] = 1; } for(i = 0; i < 26; i ++) { for(j = i; j < 52; j ++) mat.a[i + 26][j] = 1; mat.a[i + 26][i + 52] = 1; } for(i = 0; i < 26; i ++) for(j = 52; j < 78 + i; j ++) mat.a[i + 52][j] = 1; for(i = 0; i < 26; i ++) for(j = 52 + i + 1; j < 104; j ++) mat.a[i + 78][j] = 1; powmod(unit, mat, N - 1); for(i = 0; i < 52; i ++) ans += unit.a[i][0]; printf("%I64d\n", ans % D); } int main() { int t; scanf("%d", &t); while(t --) { scanf("%d", &N); solve(); } return 0; }