hdu 3658(矩阵快速幂)

来源:互联网 发布:网络教育英语统考时间 编辑:程序博客网 时间:2024/06/03 22:52

题意:一个长度为m的字符串需要填充,填充字母必须是’A’ ~ ‘Z’,’a’ ~ ‘z’,要求字符串相邻字符的ascii值的差值≤32,且必须至少存在一个相邻字符差值等于32。问有多少种填充方式。
题解:直接构造至少存在一个相邻字符差值等于32的不好做,可以逆着想,先求出差值>=32的所有情况,再求出差值<32的所有情况,两个结果相减就是解。

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;const int MOD = 1000000007;struct Mat {    long long g[55][55];}ori, res, ori2, res2;long long m;Mat multiply(Mat x, Mat y) {    Mat temp;    for (int i = 0; i < 52; i++)        for (int j = 0; j < 52; j++) {            temp.g[i][j] = 0;            for (int k = 0; k < 52; k++)                temp.g[i][j] = (temp.g[i][j] + x.g[i][k] * y.g[k][j]) % MOD;        }    return temp;}void calc1(long long m) {    while (m) {        if (m & 1)            ori2 = multiply(ori2, res2);        m >>= 1;        res2 = multiply(res2, res2);    }}void calc2(long long m) {    while (m) {        if (m & 1)            ori = multiply(ori, res);        m >>= 1;        res = multiply(res, res);    }}int main() {    int t;    scanf("%d", &t);    while (t--) {        scanf("%lld", &m);        memset(res.g, 0, sizeof(res.g));        memset(ori.g, 0, sizeof(ori.g));        memset(res2.g, 0, sizeof(res2.g));        memset(ori2.g, 0, sizeof(ori2.g));        for (int i = 0; i < 26; i++) {            for (int j = 0; j <= i + 26; j++)                res.g[j][i] = res2.g[j][i] = 1;            res2.g[i + 26][i] = 0;        }        for (int i = 26; i < 52; i++) {            for (int j = 51; j >= i - 26; j--)                res.g[j][i] = res2.g[j][i] = 1;            res2.g[i - 26][i] = 0;        }        for (int i = 0; i < 52; i++)            ori.g[0][i] = ori2.g[0][i] = 1;        calc1(m - 1);        calc2(m - 1);        long long ans1 = 0, ans2 = 0;        for (int i = 0; i < 52; i++) {            ans1 = (ans1 + ori.g[0][i]) % MOD;            ans2 = (ans2 + ori2.g[0][i]) % MOD;        }        printf("%lld\n", (ans1 + MOD - ans2) % MOD);    }    return 0;}
0 1
原创粉丝点击