Codeforces Round #248 (Div. 1)C(AC自动机+DP)

C. Tachibana Kanade's Tofu
time limit per test
5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Tachibana Kanade likes Mapo Tofu very much. One day, the canteen cooked all kinds of tofu to sell, but not all tofu is Mapo Tofu, only those spicy enough can be called Mapo Tofu.

Each piece of tofu in the canteen is given a m-based number, all numbers are in the range [l, r] (l and r being m-based numbers), and for every m-based integer in the range [l, r], there exists a piece of tofu with that number.

To judge what tofu is Mapo Tofu, Tachibana Kanade chose n m-based number strings, and assigned a value to each string. If a string appears in the number of a tofu, the value of the string will be added to the value of that tofu. If a string appears multiple times, then the value is also added that many times. Initially the value of each tofu is zero.

Tachibana Kanade considers tofu with values no more than k to be Mapo Tofu. So now Tachibana Kanade wants to know, how many pieces of tofu are Mapo Tofu?

Input

The first line contains three integers nm and k (1 ≤ n ≤ 200; 2 ≤ m ≤ 20; 1 ≤ k ≤ 500). Where n denotes the number of strings, mdenotes the base used, and k denotes the limit of the value for Mapo Tofu.

The second line represents the number l. The first integer in the line is len (1 ≤ len ≤ 200), describing the length (number of digits in base m) of l. Then follow len integers a1, a2, ..., alen (0 ≤ ai < ma1 > 0) separated by spaces, representing the digits of l, with a1being the highest digit and alen being the lowest digit.

The third line represents the number r in the same format as l. It is guaranteed that 1 ≤ l ≤ r.

Then follow n lines, each line describing a number string. The i-th line contains the i-th number string and vi — the value of the i-th string (1 ≤ vi ≤ 200). All number strings are described in almost the same format as l, the only difference is number strings may contain necessary leading zeros (see the first example). The sum of the lengths of all number strings does not exceed 200.

Output

Output the number of pieces of Mapo Tofu modulo 1000000007 (109 + 7). The answer should be a decimal integer.

Sample test(s)
input
2 10 1
1 1
3 1 0 0
1 1 1
1 0 1
output
97
input
2 10 12
2 5 9
6 6 3 5 4 9 7
2 0 6 1
3 6 7 2 1
output
635439
input
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
output
2
Note

In the first sample, 10, 11 and 100 are the only three decimal numbers in [1, 100] with a value greater than 1. Here the value of 1 is 1 but not 2, since numbers cannot contain leading zeros and thus cannot be written as "01".

In the second sample, no numbers in the given interval have a value greater than 12.

In the third sample, 110000 and 110001 are the only two binary numbers in the given interval with a value no greater than 6.

题意:RT

思路:最暴力的想法是枚举l到r之间的所有m进制数,然后对每个数字判断是不是Mapo Tofu,这样显然也只能想想

 如何优化呢?同样也是枚举数字,只是现在的枚举方式是从高位往低位一位一位的填数字,可以将区间分为[1,r],[1,l-1],以求[1,r]为例,每次往后

 填的数字显然有m种填法,不过当现在数字是r的前缀的时候,假设填到了i位,则第i+1位只有r[i+1]种填法,因为要保证不能超过r

 怎么和AC自动机联系起来呢?用dp[i][j][z][flag][is]表示当前状态为枚举到了i位,且在AC自动机中的节点id为j,权值不超过z,flag=0表示不是r的

 前缀,为1表示是r的前缀,is=1表示前面全是0,然后转移就很好想了。

 感觉说的不是很清楚,官方题解http://codeforces.com/blog/entry/12397

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
         
           #include 
          
            #include 
           
             using namespace std; const int MOD = (int)1e9+7; const int MAXN = 205; int to[MAXN][21]; int f[MAXN]; int last[MAXN]; int sz; int val[MAXN]; int ww[MAXN]; int add(int x,int y) { x+=y; if(x>=MOD)x-=MOD; return x; } int sub(int x,int y) { x-=y; if(x<0)x+=MOD; return x; } void build(char *s,int v) { int l=strlen(s); int j=0; for(int i=0;i 
            
              q; void bfs() { for(int i=0;i<21;i++) if(to[0][i]){ q.push(to[0][i]); f[to[0][i]]=0; last[to[0][i]]=0; } while(!q.empty()){ int r=q.front();q.pop(); for(int i=0;i<21;i++){ int u=to[r][i]; if(!u)continue; q.push(u); int j=f[r]; while(j && !to[j][i])j=f[j]; f[u]=to[j][i]; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } int res; void print(int j) { if(j==0)return; if(val[j])res+=ww[j]; print(last[j]); } int b[MAXN][2]; int dp[MAXN][MAXN][505][2][2]; int ans[2]; int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); int r[2]; scanf("%d",&r[0]); for(int i=1;i<=r[0];i++) scanf("%d",&b[i][0]); scanf("%d",&r[1]); for(int i=1;i<=r[1];i++) scanf("%d",&b[i][1]); for(int i=0;i 
             
               k)continue; dp[i+1][jj][nres][nflag][nis] = add( dp[i+1][jj][nres][nflag][nis] , dp[i][j][z][flag][is]); } } } for(int j=0;j<=sz;j++) for(int flag=0;flag<2;flag++) for(int z=0;z<=k;z++) ans[kk]=add(ans[kk],dp[r[kk]][j][z][flag][0]); } ans[0]=sub(ans[1],ans[0]); res=0; int j=0; for(int i=1;i<=r[0];i++){ int u=b[i][0]; while(j&&!to[j][u])j=f[j]; j=to[j][u]; print(j); } if(res<=k)ans[0]=add(ans[0],1); printf("%d\n",ans[0]); return 0; } 
              
             
            
           
          
        
       
       
      
      
     
     
    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值