LGP3311题解
2024-10-16 08:12:23
为什么我和同学对比了一下,发现我和他的做法差别很大啊
对于这种问题,我们把整个字符串分为两个部分:前缀顶着最高位和后缀没有顶着最高位。
我们枚举这个前缀,然后后缀通过 DP 来搞定。
不包含任何一个子串,似乎最有力的处理工具就是 ACAM。
于是我们可以确定这个 DP 的状态:\(dp[k][u]\) 表示从自动机的节点 \(u\) 上走 \(k\) 条边都遇不上被标记点的方案数。
转移:\(dp[k][u]\) 从 \(dp[k-1][trans[u][c]]\) 转移过来就好了。
但是这样会有一个问题:枚举出来的正整数含有前导 \(0\)。
考虑加上被判断成不合法的方案。我们枚举前导 \(0\) 的数量,然后将正整数分为四类:
//加前导0合法 / 不加前导0合法 - a
//加前导0合法 / 不加前导0不合法 - b=0
//加前导0不合法 / 不加前导0合法 - c
//加前导0不合法 / 不加前导0不合法 - d
可以发现我们原本计算的是 \(a+b\),但是我们需要计算 \(a+c\)。
枚举了前导 \(0\) 后,直接减去 \(a+b\) 然后加上 \(a+c\) 就可以了(
具体的话维护一个节点,每次都往 \(0\) 方向走就行了。
#include<cstring>
#include<cstdio>
#include<cctype>
typedef unsigned ui;
const ui M=1505,mod=1e9+7;
ui n,m,tot(1),dp[M][M],fail[M],trans[M][10];bool vis[M];char s[M],S[M];
inline void Insert(char*s){
ui u(1);
while(isdigit(*s)){
const ui&c=*s-48;*s++=0;
if(!trans[u][c])trans[u][c]=++tot;
u=trans[u][c];
}
vis[u]=true;
}
inline void Build(){
static ui L,R,q[M];L=1;
for(ui c=0;c<10;++c){
if(trans[1][c])q[++R]=trans[1][c],fail[trans[1][c]]=1;
else trans[1][c]=1;
}
while(L<=R){
const ui&u=q[L++];
for(ui c=0;c<10;++c){
if(trans[u][c])q[++R]=trans[u][c],fail[trans[u][c]]=trans[fail[u]][c];
else trans[u][c]=trans[fail[u]][c];
}
}
for(ui i=1;i<=R;++i)vis[q[i]]|=vis[fail[q[i]]];
}
signed main(){
ui ans(0);
scanf("%s%u",s+1,&n);m=strlen(s+1);
for(ui i=1;i<=n;++i){
scanf("%s",S);Insert(S);
}
Build();
for(ui u=1;u<=tot;++u)if(!vis[u])dp[0][u]=1;
for(ui i=1;i<=m;++i){
for(ui u=1;u<=tot;++u)if(!vis[u]){
for(ui c=0;c<10;++c)dp[i][u]=(dp[i][u]+dp[i-1][trans[u][c]])%mod;
}
}
ui u(1),now(1);
for(ui i=1;i<=m;++i){
if(vis[u])break;now=trans[now][0];
for(ui c=0;c<s[i]-48;++c)if(!vis[trans[u][c]])ans=(ans+dp[m-i][trans[u][c]])%mod;
if(i!=m)for(ui c=1;c<10;++c)ans=(ans+mod+dp[m-i-1][trans[1][c]]-dp[m-i-1][trans[now][c]])%mod;
u=trans[u][s[i]-48];
}
if(!vis[u])++ans,ans==mod&&(ans=0);
printf("%u",(ans+mod-1)%mod);
}
最新文章
- September 28th 2016 Week 40th Wednesday
- 使用CSS将图片转换成黑白(灰色、置灰)z转
- 使用Aspose插件将程序中的表格,导出生成excel表格
- Linux/Ubuntu tree 命令以树形结构显示文件夹目录结构
- UEFI双硬盘安装win8.1和Ubuntu14.04
- Debian下MySQL配置
- vs2013编译qt程序后中文出现乱码
- EXCEL 操作
- caption标签,为表格添加标题和摘要
- 【USACO 1.5.1】数字金字塔
- progID
- dva框架使用mock.js模拟数据 + fetch请求数据
- Chrome打不开Pycharm运行的web应用
- 《Office 365 开发入门指南》公开邀请试读,欢迎反馈
- Jumpstart for Oracle Service Bus Development
- 利用广度优先搜索(BFS)与深度优先搜索(DFS)实现岛屿个数的问题(java)
- webpack打包vue -->;简易讲解
- bzoj1040 基环树森林dp
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十九):服务消费(Ribbon、Feign)
- hdoj:2029