JZOJ 3363 【NOI2013模拟】Number

来源:互联网 发布:扭曲验证码识别 python 编辑:程序博客网 时间:2024/06/03 20:59

题目大意:

现在要组成一个长度为11且开头为1的数字串,有n(1<=n<=100)个长度小于等于5的数字串,现在把组成的字符串分成三段,有四种分法:
1. xxx-xxx-xxxxx 例如 151-958-83019
2. xxx-xxxx-xxxx 例如 151-9588-3019
3. xxxx-xxxx-xxx 例如 1519-5883-019
4. xxxx-xxx-xxxx 例如 1519-588-3019
要求每一段都不包含那个n串,有多少种方案。

题解:

比赛时直接预处理了一下接着暴力,然后梦想地过了。
题解说,对n个串建一个AC自动机,设fi,S表示走了i步,在自动机上的状态为S的方案数,然后设g(i)表示在各种分法中,比它小的最大的边界,判一下,不合法就不传。
给出暴力标:

#include<cstdio>#include<cstring>#define ll long long#define fo(i, x, y) for(int i = x; i <= y; i ++)#define fd(i, x, y) for(int i = x; i >= y; i --)using namespace std;int n, a10[20], a[101][2], f[12][100000];char c[10];int d[100000][101];int b[10][2] = {{0, 0}, {5, 5}, {4, 4}, {3, 3}, {8, 3}, {8, 4}, {7, 4}, {7, 3}, {11, 3}, {11, 4}};int main() {    a10[0] = 1; fo(i, 1, 9) a10[i] = a10[i - 1] * 10;    scanf("%d", &n);    fo(i, 1, n) {        scanf("%s", c + 1);        a[i][1] = strlen(c + 1); a[i][0] = 0;         fd(j, a[i][1], 1) a[i][0] = a[i][0] * 10 + c[j] - 48;    }    fo(i, 1, n) {        fo(j, 0, 99999) {            int bz = 0;            fo(w, 1, 6 - a[i][1])                if((j % a10[a[i][1] + w - 1]) / a10[w - 1] == a[i][0]) {                    bz = w + a[i][1] - 1; break;                 }            if(bz) d[j][++ d[j][0]] = bz;        }    }    f[0][0] = 1;    fo(i, 1, 11) {        fo(j, 0, 99999) fo(num, 0, 9) f[i][j % a10[4] * 10 + num] += f[i - 1][j];        fo(k, 1, 9) if(b[k][0] == i){            fo(j, 0, 99999) if(f[i][j] > 0) {                fo(u, 1, d[j][0]) if(d[j][u] <= b[k][1]) {                    f[i][j] = 0; break;                }            }        }    }    ll ans = 0;    fo(i, 0, 99999) if(i % 10 == 1) ans += f[11][i];    printf("%lld\n", ans);}
原创粉丝点击