[BZOJ2326][HNOI2011]数学作业(矩乘)

来源:互联网 发布:汕头峡山淘宝拍摄 编辑:程序博客网 时间:2024/06/14 15:38

考虑求Concatenate(L...R)的值,其中[L,R]之间的数都是x位数。
可以得到,Concatenate(L...i)可以用递推式表示。以下设Concatenate(L...i)f[i]
则有:
f[L]=L
f[i]=f[i1]10x+i
建立一个33的转移矩阵P,第一行代表f[i],第二行代表i,第三行代表1。则容易得出矩阵内容:

10x00110111

31的边界矩阵F
LL1

此时可以得出,f[R]=(PRLF)[1][1]
用这样的方法,就可以求出Concatenate(1...9)Concatenate(10...99)Concatenate(100...999),…,Concatenate(10k,N)的值,然后乱搞即可。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;ll nn, E10[1005]; int CYX, Exp[1005], np[25];struct cyx {    int m, n, a[15][15];    cyx() {}    cyx(int _m, int _n) :        m(_m), n(_n) {memset(a, 0, sizeof(a));}    friend inline cyx operator * (cyx x, cyx y) {        cyx z = cyx(x.m, y.n); int i, j, k;        for (i = 1; i <= z.m; i++) for (j = 1; j <= z.n; j++)        for (k = 1; k <= x.n; k++)            (z.a[i][j] += 1ll * x.a[i][k] * y.a[k][j] % CYX)                %= CYX;        return z;    }    friend inline cyx operator ^ (cyx x, ll y) {        cyx aa = x, z = cyx(x.m, x.n); int i;        for (i = 1; i <= z.m; i++) z.a[i][i] = 1;        while (y) {            if (y & 1) z = z * aa;            aa = aa * aa;            y >>= 1;        }        return z;    }} F, P;int qpow(int a, ll b) {    int res = 1;    while (b) {        if (b & 1) res = 1ll * res * a % CYX;        a = 1ll * a * a % CYX;        b >>= 1;    }    return res;}int solve(int w, ll mx) {    F.a[1][1] = F.a[2][1] = Exp[w - 1];    F.a[3][1] = 1; P.a[1][1] = Exp[w];    F = (P ^ mx - E10[w - 1]) * F;    return F.a[1][1];}inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}int main() {    int i, cnt = 0, res = 0;    cin >> nn; CYX = read(); Exp[0] = E10[0] = 1;    for (i = 1; i <= 1000; i++)        Exp[i] = 1ll * Exp[i - 1] * 10 % CYX;    for (i = 1; i <= 18; i++) E10[i] = E10[i - 1] * 10;    F = cyx(3, 1); P = cyx(3, 3);    P.a[1][2] = P.a[1][3] = P.a[2][2]    = P.a[2][3] = P.a[3][3] = 1; ll bb = nn;    while (bb) cnt++, bb /= 10;    for (i = 1; i <= cnt; i++) {        ll mx = i == cnt ? nn : E10[i] - 1;        res = 1ll * res *            qpow(qpow(10, mx - E10[i - 1] + 1), i) % CYX;        (res += solve(i, mx)) %= CYX;    }    printf("%d\n", res);    return 0;}
原创粉丝点击