省选模拟题 T1 A

来源:互联网 发布:大数据hadoop应用 编辑:程序博客网 时间:2024/06/09 13:28

模拟题 T1 A

Description
现在有无数个HJA,编号从1一直到无穷。对于编号为x的 HJA,我们考虑如何计算他的价值。我们将x写作m制的数,然后考虑我们给出的另外nm进制下的数(这些数可能有前导零),每个数的权值为vi。如果第i个数在x中出现了r次(在匹配的时候 HJA是没有前导零的,但这些数的前导零也必须被匹配),那么我们便把x的价值加上r×vi,所以编号为x的HJA的权值应该是ki=1ri×vi。现在HJA 希望知道[l,r]中有多少个 HJA 的价值是不超过k的。
Input
第一行是三个正整数n,m,k
第二行第一个整数lenl代表l的位数, 接下来lenl个整数代表lm进制下的每一位。
第三行第一个整数lenr代表r的位数,接下来lenr个整数代表rm进制下的每一位。
接下来n行, 每行第一个数代表第i个数的长度,接下来的读入方式同l,r。最后有一个数代表这个数的权值。
Output
输出答案模109+7
Sample Input 1
2 10 1
1 1
3 1 0 0
1 1 0
1 0 1
Sample Output 1
97

Sample Input 2
2 10 12
2 5 9
6 6 3 5 4 9 7
2 0 6 1
3 6 7 2 1
Sample Output 2
635439

Sample Input 3
4 2 6
6 1 0 1 1 1 0
6 1 1 0 1 0 0
1 1 2
3 0 1 0 5
4 0 1 1 0 4
3 1 0 1 2
Sample Output 3
2

Solution
该题是一个比较裸的动态规划题,思维难度并不高。考虑n个数与一个数的匹配过程,实际上就是字符串问题中的多串匹配问题,所以我们对这n个串建立AC自动机。那么对于一个特定的数,我们只要在该AC自动机上走一遍就能知道n个数的每一个数分别出现了多少次,从而算出这个数的权值。
考虑另外一部分,我们要求[l,r]之间满足条件的数的个数,等价于求[1,r][1,l1]内满足条件的数的个数,然后相减即可。这样问题就变成了一个经典的数位DP问题,记f[i][j][k][l]表示我们现在已经填好了这个数的前i位同时走到了AC自动机的第k个状态,当前的价值是k的方案数。l0/1变量,表示当前数是等于上界值还是小于上界值,转移的方法枚举下一位所填的数即可。

Program

#include <cstdio>#include <iostream>#include <cstdlib>#include <algorithm>#include <queue>#include <cstring>using namespace std ;const int N=210;const int M=25;const int K=510;const int mod=1e9+7;#define newnode ++tlen#define inc(a,b) {a+=b; if (a>=mod) a-=mod;}int f[N][N][K][2];//DP数组int q[N];int n,m,k;int word[N][N],wlen[N];//存储有权单词及其长度int tlen,root;//trie树的节点个数,trie树根节点编号int le[N],ri[N],llen,rlen;//左边界和右边界typedef struct Trie{    int next[M];    int value,fail;    Trie (){        memset (next,0,sizeof(next));        value=fail=0;    }}T;T trie[N];void T_insert (int *s,int l,int v){    int p=root,i;    for (i=1;i<=l;i++){        if (!trie[p].next[s[i]]) trie[p].next[s[i]]=newnode;        p=trie[p].next[s[i]];    }    trie[p].value+=v;}void init (){    scanf ("%d %d %d",&n,&m,&k);    int i,j,v;    root=newnode;    scanf ("%d",&llen);    for (i=llen;i>=1;i--) scanf ("%d",&le[i]);    scanf ("%d",&rlen);    for (i=rlen;i>=1;i--) scanf ("%d",&ri[i]);    for (i=1;i<=n;i++){        scanf ("%d ",&wlen[i]);        for (j=wlen[i];j>=1;j--){            scanf ("%d ",&word[i][j]);        }        scanf ("%d",&v);        T_insert(word[i],wlen[i],v);    }}void build_ACaotomaton (){    int front=1,tail=1;    int now,i,p;    q[1]=root;    while (front<=tail){        now=q[front++];        for (i=0;i<m;i++){            if (trie[now].next[i]){                p=trie[now].fail;                while (p){                    if (trie[p].next[i]){                        trie[trie[now].next[i]].fail=trie[p].next[i];                        break;                    }                    p=trie[p].fail;                }                if (!p) trie[trie[now].next[i]].fail=root;                trie[trie[now].next[i]].value+=trie[trie[trie[now].next[i]].fail].value;                q[++tail]=trie[now].next[i];            }            else {                trie[now].next[i]=trie[trie[now].fail].next[i];                if (!trie[now].next[i]) trie[now].next[i]=root;            }        }    }}int solve(int *y,int l){    if (!l) return 0;    int ans=0;    int a,b,c,d,e;    int p,data;    for (a=1;a<l;a++)        for (b=1;b<=tlen;b++)            for (c=0;c<=k;c++)                inc(ans,f[a][b][c][0]);    for (a=l;a>=1;a--){        for (b=1;b<=tlen;b++){            for (c=(a==l);c+(a!=1)<=y[a];c++){                p=b;                data=0;                p=trie[p].next[c];                data+=trie[p].value;                for (d=a+1;d<=l;d++){                    p=trie[p].next[y[d]];                    data+=trie[p].value;                }                for (d=0;d<=k-data;d++){                    for (e=0;e<=1;e++) inc(ans,f[a-1][b][d][e]);                }            }        }    }    return ans;}int main (){    init ();    build_ACaotomaton ();    n=max (llen,rlen);    f[0][root][0][0]=1;    int a,b,c,d,e,i;    for (a=0;a<n;a++)        for (b=1;b<=tlen;b++)            for (c=0;c<=k;c++)                for (d=0;d<=1;d++)                    if (f[a][b][c][d])                        for (e=0;e<m;e++)                            if (c+trie[trie[b].next[e]].value<=k)                                inc(f[a+1][trie[b].next[e]][c+trie[trie[b].next[e]].value][e==0],f[a][b][c][d]);    le[1]--;    for (i=1;i<=llen;i++){        if (le[i]<0) {            le[i]+=m;            le[i+1]--;        }        else break;    }    if (!le[llen]) llen--;    printf("%d\n",(solve(ri,rlen)-solve(le,llen)+mod)%mod);    return 0;}
0 0