题目传送门(内部题19)


输入格式

第一行两个正整数$n,k$,代表秘钥个数和要求。
接下来两个正整数$x$和$y$,意义如题所述。
接下来$n$行,每行一个正整数,意义如题所述。


输出格式

一个正整数,代表密码的种数模$1000000007(10^9+7)$的值。


样例

样例输入:

3 1
2 20
2 4 9

样例输出:

6


数据范围与提示

样例解释:

这$6$个密码为$4,9,12,14,19,20$。

数据范围:

设$s=\max(x$的长度$,y$的长度$),S=\sum$秘钥的长度。
对于$30\%$的数据,$0\leqslant x<y\leqslant 100,000,1\leqslant n\leqslant 10,1\leqslant k\leqslant 5,n\leqslant S\leqslant 20$。
对于另外$20\%$的数据,$1\leqslant n\leqslant 100,1\leqslant y−x\leqslant 100,000,1\leqslant k\leqslant 10,n\leqslant S\leqslant 200$。
对于另外$10\%$的数据,$n=k=1,1\leqslant s\leqslant 500$,秘钥为$666$。
对于另外$10\%$的数据,$n=k=1,1\leqslant s\leqslant 500$,秘钥为$233$。
对于$100\%$的数据,$1\leqslant s\leqslant 500,1\leqslant n\leqslant 100,n\leqslant S\leqslant 200,1\leqslant k\leqslant 10$。
$Warning$:可能存在相同的秘钥,应该算作多次。


题解

看出来了$AC$自动机,看出来了数位$DP$,然后你也看到了祖宗……

考虑如何在$AC$自动机上跑数位$DP$,定义$dp[i][j][k][0/1]$表示到了第$i$个数字,在$AC$自动机上的第$j$个节点,已经匹配了$k$个密钥,是否有限制。

时间复杂度:$\Theta(40\times s\times S\times k)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. long long n,K;
  4. long long x[600],y[600],a[600],m[600];
  5. char xx[600],yy[600],aa[600];
  6. long long s[600];
  7. long long trie[600][20],ed[600],nxt[600],que[600],cnt;
  8. long long dp[600][500][20][2];
  9. void insert(long long *a)
  10. {
  11. int p=0;
  12. for(int i=1;i<=a[0];i++)
  13. {
  14. if(!trie[p][a[i]])trie[p][a[i]]=++cnt;
  15. p=trie[p][a[i]];
  16. }
  17. ed[p]++;
  18. }
  19. void build()
  20. {
  21. int head=1,tail=1;
  22. while(head<=tail)
  23. {
  24. for(int i=0;i<10;i++)
  25. {
  26. if(!trie[que[head]][i])continue;
  27. int flag=nxt[que[head]];
  28. while(!trie[flag][i]&&flag)flag=nxt[flag];
  29. que[++tail]=trie[que[head]][i];
  30. if(trie[flag][i]!=trie[que[head]][i])nxt[que[tail]]=trie[flag][i];
  31. ed[que[tail]]+=ed[nxt[que[tail]]];
  32. }
  33. head++;
  34. }
  35. }
  36. long long getans1()
  37. {
  38. memset(dp,0,sizeof(dp));
  39. s[x[0]+1]=1;
  40. for(int i=x[0];i;i--)s[i]=(s[i+1]+m[x[0]-i]*x[i]%1000000007)%1000000007;
  41. dp[0][0][0][1]=1;
  42. int flag1,flag2=0;
  43. for(int i=0;i<=x[0];i++)
  44. {
  45. for(int j=0;j<=cnt;j++)
  46. {
  47. for(int k=0;k<K;k++)
  48. {
  49. if(i==x[0])break;
  50. if(dp[i][j][k][0])
  51. {
  52. for(int l=0;l<=9;l++)
  53. {
  54. flag1=j;
  55. while(!trie[flag1][l]&&flag1)flag1=nxt[flag1];
  56. if(trie[flag1][l])flag1=trie[flag1][l];
  57. dp[i+1][flag1][min(K,k+ed[flag1])][0]=(dp[i+1][flag1][min(K,k+ed[flag1])][0]+dp[i][j][k][0])%1000000007;
  58. }
  59. }
  60. if(dp[i][j][k][1])
  61. {
  62. for(int l=0;l<x[i+1];l++)
  63. {
  64. flag1=j;
  65. while(!trie[flag1][l]&&flag1)flag1=nxt[flag1];
  66. if(trie[flag1][l])flag1=trie[flag1][l];
  67. dp[i+1][flag1][min(K,k+ed[flag1])][0]=(dp[i+1][flag1][min(K,k+ed[flag1])][0]+dp[i][j][k][1])%1000000007;
  68. }
  69. flag1=j;
  70. while(!trie[flag1][x[i+1]]&&flag1)flag1=nxt[flag1];
  71. if(trie[flag1][x[i+1]])flag1=trie[flag1][x[i+1]];
  72. dp[i+1][flag1][min(K,k+ed[flag1])][1]=(dp[i+1][flag1][min(K,k+ed[flag1])][1]+dp[i][j][k][1])%1000000007;
  73. }
  74. }
  75. flag2=(flag2+dp[i][j][K][0]*m[x[0]-i]%1000000007+dp[i][j][K][1]*s[i+1]%1000000007)%1000000007;
  76. }
  77. }
  78. return flag2;
  79. }
  80. long long getans2()
  81. {
  82. memset(dp,0,sizeof(dp));
  83. s[y[0]+1]=1;
  84. for(int i=y[0];i;i--)s[i]=(s[i+1]+m[y[0]-i]*y[i]%1000000007)%1000000007;
  85. dp[0][0][0][1]=1;
  86. int flag1,flag2=0;
  87. for(int i=0;i<=y[0];i++)
  88. {
  89. for(int j=0;j<=cnt;j++)
  90. {
  91. for(int k=0;k<K;k++)
  92. {
  93. if(i==y[0])break;
  94. if(dp[i][j][k][0])
  95. {
  96. for(int l=0;l<=9;l++)
  97. {
  98. flag1=j;
  99. while(!trie[flag1][l]&&flag1)flag1=nxt[flag1];
  100. if(trie[flag1][l])flag1=trie[flag1][l];
  101. dp[i+1][flag1][min(K,k+ed[flag1])][0]=(dp[i+1][flag1][min(K,k+ed[flag1])][0]+dp[i][j][k][0])%1000000007;
  102. }
  103. }
  104. if(dp[i][j][k][1])
  105. {
  106. for(int l=0;l<y[i+1];l++)
  107. {
  108. flag1=j;
  109. while(!trie[flag1][l]&&flag1)flag1=nxt[flag1];
  110. if(trie[flag1][l])flag1=trie[flag1][l];
  111. dp[i+1][flag1][min(K,k+ed[flag1])][0]=(dp[i+1][flag1][min(K,k+ed[flag1])][0]+dp[i][j][k][1])%1000000007;
  112. }
  113. flag1=j;
  114. while(!trie[flag1][y[i+1]]&&flag1)flag1=nxt[flag1];
  115. if(trie[flag1][y[i+1]])flag1=trie[flag1][y[i+1]];
  116. dp[i+1][flag1][min(K,k+ed[flag1])][1]=(dp[i+1][flag1][min(K,k+ed[flag1])][1]+dp[i][j][k][1])%1000000007;
  117. }
  118. }
  119. flag2=(flag2+dp[i][j][K][0]*m[y[0]-i]%1000000007+dp[i][j][K][1]*s[i+1]%1000000007)%1000000007;
  120. }
  121. }
  122. return flag2;
  123. }
  124. int main()
  125. {
  126. scanf("%lld%lld%s%s",&n,&K,xx+1,yy+1);
  127. x[0]=strlen(xx+1);
  128. y[0]=strlen(yy+1);
  129. m[0]=1;
  130. for(int i=1;i<=500;i++)m[i]=m[i-1]*10%1000000007;
  131. for(int i=1;i<=x[0];i++)x[i]=xx[i]-'0';
  132. for(int i=1;i<=y[0];i++)y[i]=yy[i]-'0';
  133. for(int i=1;i<=n;i++)
  134. {
  135. scanf("%s",aa+1);
  136. a[0]=strlen(aa+1);
  137. for(int j=1;j<=a[0];j++)a[j]=aa[j]-'0';
  138. insert(a);
  139. }
  140. build();
  141. printf("%lld",(getans2()-getans1()+1000000007)%1000000007);
  142. return 0;
  143. }

rp++

[CSP-S模拟测试]:密码(AC自动机+DP)的更多相关文章

  1. BZOJ1559[JSOI2009]密码——AC自动机+DP+搜索

    题目描述 输入 输出 样例输入 10 2 hello world 样例输出 2 helloworld worldhello 提示 这题算是一个套路题了,多个串求都包含它们的长为L的串的方案数. 显然是 ...

  2. [CSP-S模拟测试]:密码(数位DP+库默尔定理)

    题目描述 为了揭穿$SERN$的阴谋,$Itaru$黑进了$SERN$的网络系统.然而,想要完全控制$SERN$,还需要知道管理员密码.$Itaru$从截获的信息中发现,$SERN$的管理员密码是两个 ...

  3. [BZOJ 1559] [JSOI2009] 密码 【AC自动机DP】

    题目链接:BZOJ - 1559 题目分析 将给定的串建成AC自动机,然后在AC自动机上状压DP. 转移边就是Father -> Son 或 Now -> Fail. f[i][j][k] ...

  4. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

  5. HDU2296 Ring(AC自动机+DP)

    题目是给几个带有价值的单词.而一个字符串的价值是 各单词在它里面出现次数*单词价值 的和,问长度不超过n的最大价值的字符串是什么? 依然是入门的AC自动机+DP题..不一样的是这题要输出具体方案,加个 ...

  6. HDU2457 DNA repair(AC自动机+DP)

    题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步) ...

  7. hdu 4117 GRE Words AC自动机DP

    题目:给出n个串,问最多能够选出多少个串,使得前面串是后面串的子串(按照输入顺序) 分析: 其实这题是这题SPOJ 7758. Growing Strings AC自动机DP的进阶版本,主题思想差不多 ...

  8. hdu 2457(ac自动机+dp)

    题意:容易理解... 分析:这是一道比较简单的ac自动机+dp的题了,直接上代码. 代码实现: #include<stdio.h> #include<string.h> #in ...

  9. HDU 2425 DNA repair (AC自动机+DP)

    DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  10. HDU2296——Ring(AC自动机+DP)

    题意:输入N代表字符串长度,输入M代表喜欢的词语的个数,接下来是M个词语,然后是M个词语每个的价值.求字符串的最大价值.每个单词的价值就是单价*出现次数.单词可以重叠.如果不止一个答案,选择字典序最小 ...

随机推荐

  1. (appium+python)UI自动化_02_appium启动手机app

    前提:需先安装配置好appium+python自动化环境,已配置好环境的小伙伴可以参考以下步骤启动Android app,具体步骤如下: 一.USB连接手机 (1)手机USB连接电脑 (2)手机打开开 ...

  2. 使用Atom写你的笔记

    使用Atom写你的笔记 本文参考简书笔记. 使用sync-settings同步你的Atom设置 使用sync-settings插件需要以下3个条件: 电脑已安装Atom Atom内已安装sync-se ...

  3. 跨域资源共享(CORS)-漏洞整理

    绕过方法整理 绕过 - 仅对域名校验 #POC #"Access-Control-Allow-Origin: https://xx.co & Access-Control-Allow ...

  4. jvm 更多链接

    http://www.cnblogs.com/dingyingsi/p/3760447.html    :  讲解 jvm https://blog.csdn.net/Luomingkui1109/a ...

  5. MySQL数据类型-整型

    ​ MySQL支持SQL标准整数类型integer(或INT)和SMALLINT.作为标准的扩展,MySQL还支持整数类型TINYINT.MEDIUMINT和BIGINT. 类型 所占字节 有符号最小 ...

  6. Scala操作外部数据

    Scala操作外部数据: 1.操作文件 2.操作XML 3.操作MySQL 读取文件: object FileApp { def main(args: Array[String]): Unit = { ...

  7. ES6---new Promise()讲解,Promise对象是用来干嘛的?

    ES6---new Promise()讲解,Promise对象是用来干嘛的? :https://blog.csdn.net/Wbiokr/article/details/79490390

  8. dp(最长公共子序列)

    A subsequence of a given sequence is the given sequence with some elements (possible none) left out. ...

  9. Codeforces 1091C (数学)

    题面 传送门 分析 假设k是固定的,那访问到的节点编号就是\(1+(a·k \mod n )\),其中a为正整数. 通过找规律不难发现会出现循环. 通过题目中的图片我们不难发现 只有k=1,2,3,6 ...

  10. 2014 SummerTrain Beautiful Garden

    There are n trees planted in lxhgww's garden. You can assume that these trees are planted along the ...