tkj
文章143
标签102
分类0
bzoj 2323: [ZJOI2011]细胞

bzoj 2323: [ZJOI2011]细胞

题外话:好像欠了很多题解。。。有空再补吧

题意:

给你一个长度为$n$的数列,将它切成若干段,每段的质量相等,然后再按每段上的数字组成的十进制数$x$把这一段分成$x$个小段,所有小段平分这一段的质量。分完之后所有小段排成一行,某些相邻的小段粘在一起,使得没有小段两边都没有和旁边的粘起来。两种结构被认为相同,当且仅当他们拥有相同个数的小段,从头到尾每个小段的质量相同,并且从头到尾每对相邻小段之间的连接情况相同。问最终有多少种结构。

题解:

首先我们想一想,如果知道了分成多少小段,最终会有多少种情况。设$f_{i, 0/1}$表示前$i$个小段,第$i$个小段有没有连着左边的小段。那么$$
f_{i, 0} = f_{i - 1, 1} \\\
f_{i, 1} = f_{i - 1, 0} + f_{i - 1, 1}

g_i = \sum_{j = 1}^i g_j \times d^{\overline{s_{j \ldots i}}}

$$
还有个问题,$\overline{s_{j \ldots i}}$超级大。我们可以一位一位搞,预处理出$d$的$10^k$次幂,然后直接乘起来就好。

代码:

#include <bits/stdc++.h>
using namespace std;

const int mod = 1000000007;
int n;
char s[1010];
struct matrix
{
    int x, y;
    long long a[2][2];
    matrix() : a() {}
    long long *operator[](int x) { return a[x]; }
} one, base[1010], f[1010];

matrix operator+(matrix x, matrix y)
{
    for (int i = 0; i < x.x; i++)
        for (int j = 0; j < x.y; j++)
            (x[i][j] += y[i][j]) %= mod;
    return x;
}
matrix operator*(matrix x, matrix y)
{
    matrix ans;
    ans.x = x.x;
    ans.y = y.y;
    for (int i = 0; i < ans.x; i++)
        for (int j = 0; j < ans.y; j++)
            for (int k = 0; k < y.x; k++)
                (ans[i][j] += x[i][k] * y[k][j] % mod) %= mod;
    return ans;
}
matrix Pow(matrix x, int y)
{
    matrix ans = one;
    for (int i = 0; i < y; i++)
        ans = ans * x;
    return ans;
}
int main()
{
    scanf("%d%s", &n, s + 1);
    one.x = one.y = 2;
    one[0][0] = one[1][1] = 1;
    base[0].x = base[0].y = 2;
    base[0][0][1] = base[0][1][0] = base[0][1][1] = 1;
    for (int i = 1; i < n; i++)
    {
        matrix hh = base[i - 1];
        base[i] = hh = hh * hh;
        hh = hh * hh;
        hh = hh * hh;
        base[i] = base[i] * hh;
    }
    f[0].x = 1;
    f[0].y = 2;
    f[0][0][0] = -1;
    f[0][0][1] = 1;
    for (int i = 1; i <= n; i++)
    {
        f[i].x = 1;
        f[i].y = 2;
        matrix hh = one;
        for (int j = i; j > 0; j--)
        {
            hh = hh * Pow(base[i - j], s[j] - '0');
            f[i] = f[i] + f[j - 1] * hh;
        }
    }
    printf("%lld\n", (f[n][0][1] + mod) % mod);
}
本文作者:tkj
本文链接:https://tkj666.github.io/126/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可