题目描述

  有一个定义在 \(\{0,1,2,3,4,5,6,7,8,9\}\) 上的合规表达式,包含三种基本的操作:

   结合:\(E_1E_2\)

   分配:\((E_1|E_2|\ldots|E_n),n\geq 2\)

   重复:\((E_1)* ,n\geq 0\)

  给你 \(l,r\),问你有多少个 \([l,r]\) 之间不含前导零的整数能匹配这个合规表达式。

  \(1\leq l\leq r\leq {10}^{18}\)

题解

  直接建出这个合规表达式对应的 NFA,在上面跑数位 DP 即可。

  记录 \(f_{i,0/1,j}\) 表示还需要确定后 \(i\) 位,前面这几位是否比 \(n\) 小,在 NFA 上面可以达到的状态集合是 \(j\) 时的方案数。

  时间复杂度:\(O(???)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll; char s[100];
int c[100];//另一个括号的位置
int n;
int st[100];
int top;
int b[100][100];//epsilon
int nxt[100];
int move(int x,int v)
{
int res=0;
for(int i=1;i<=n+1;i++)
if(((x>>(i-1))&1)&&s[i]-'0'==v)
res|=nxt[i+1];
return res;
}
void init()
{
memset(c,0,sizeof c);
top=0;
for(int i=1;i<=n;i++)
if(s[i]=='(')
st[++top]=i;
else if(s[i]==')')
{
c[i]=st[top];
c[st[top]]=i;
top--;
}
memset(b,0,sizeof b);
for(int i=1;i<=n+1;i++)
b[i][i]=1;
for(int i=1;i<=n;i++)
if(s[i]=='(')
{
if(s[c[i]+1]=='*')
{
b[i][c[i]]=1;
b[i][i+1]=1;
}
else
{
b[i][i+1]=1;
int cnt=0;
for(int j=i;j<=c[i];j++)
{
if(s[j]=='(')
cnt++;
else if(s[j]==')')
cnt--;
if(s[j]=='|'&&cnt==1)
{
b[i][j+1]=1;
b[j][c[i]]=1;
}
}
}
}
else if(s[i]==')')
{
b[i][i+1]=1;
if(s[i+1]=='*')
b[i][c[i]]=1;
}
else if(s[i]=='*')
b[i][i+1]=1; for(int k=1;k<=n+1;k++)
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n+1;j++)
b[i][j]|=b[i][k]&&b[k][j];
memset(nxt,0,sizeof nxt);
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n+1;j++)
if(b[i][j])
nxt[i]|=1<<(j-1);
}
int len;
int a[100];
map<int,ll> f[100][2];
ll calc(ll m)
{
if(!m)
return 0;
len=0;
while(m)
{
a[++len]=m%10;
m/=10;
}
for(int i=0;i<=len;i++)
{
f[i][0].clear();
f[i][1].clear();
}
for(int i=1;i<=a[len];i++)
f[len-1][i==a[len]][move(nxt[1],i)]++;
for(int i=len-1;i>=1;i--)
for(int j=1;j<=9;j++)
f[i-1][0][move(nxt[1],j)]++;
for(int i=len;i>=1;i--)
{
for(auto v:f[i][1])
if(v.first)
{
for(int j=0;j<=a[i];j++)
f[i-1][j==a[i]][move(v.first,j)]+=v.second;
}
for(auto v:f[i][0])
if(v.first)
{
for(int j=0;j<=9;j++)
f[i-1][0][move(v.first,j)]+=v.second;
}
}
ll res=0;
for(int i=0;i<=1;i++)
for(auto v:f[0][i])
if((v.first>>n)&1)
res+=v.second;
return res;
}
void solve()
{
ll l,r;
scanf("%lld%lld",&l,&r);
scanf("%s",s+1);
n=strlen(s+1);
init();
ll ans1=calc(r);
ll ans2=calc(l-1);
ll ans=ans1-ans2;
printf("%lld\n",ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int t;
scanf("%d",&t);
while(t--)
solve();
return 0;
}

【XSY3139】预言家 数位DP NFA的更多相关文章

  1. 【BZOJ1662】[Usaco2006 Nov]Round Numbers 圆环数 数位DP

    [BZOJ1662][Usaco2006 Nov]Round Numbers 圆环数 Description 正如你所知,奶牛们没有手指以至于不能玩"石头剪刀布"来任意地决定例如谁 ...

  2. bzoj1026数位dp

    基础的数位dp 但是ce了一发,(abs难道不是cmath里的吗?改成bits/stdc++.h就过了) #include <bits/stdc++.h> using namespace ...

  3. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  4. HDU2089 不要62[数位DP]

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. 数位DP GYM 100827 E Hill Number

    题目链接 题意:判断小于n的数字中,数位从高到低成上升再下降的趋势的数字的个数 分析:简单的数位DP,保存前一位的数字,注意临界点的处理,都是套路. #include <bits/stdc++. ...

  6. 数位dp总结

    由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...

  7. 数位DP入门

    HDU 2089 不要62 DESC: 问l, r范围内的没有4和相邻62的数有多少个. #include <stdio.h> #include <string.h> #inc ...

  8. 数位DP之奥义

    恩是的没错数位DP的奥义就是一个简练的dfs模板 int dfs(int position, int condition, bool boundary) { ) return (condition ? ...

  9. 浅谈数位DP

    在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...

随机推荐

  1. C#字符串倒置函数的代码

    把内容过程比较常用的内容珍藏起来,下边内容内容是关于C#字符串倒置函数的内容. public static string Reverse(string ReverseString) { String ...

  2. Mac上webstorm与git仓库建立连接

    1.打开Mac终端,输入$ cd ~/.ssh检查.ssh文件是否存在($在终端中存在,不需要自己输入),不存在,进行步骤2 2.如果没有安装ssh文件,输入命令$ssh -v,安装ssh文件,成功时 ...

  3. 动态更新Icon

    动态更改图标主要用到activity-alias和PackageManager的setComponentEnabledSetting方法.具体步骤如下: 1.在AndroidManifest.xml中 ...

  4. 基于raspberry搭建个人web server

    树莓派系统介绍 安装操作系统及网络\远程控制配置 安装常用软件 构建web服务器(nginx + php + sqlite) 构建web服务器(appach+mysql+php) 构建NAS服务器 其 ...

  5. C#开发WEBService服务 C++开发客户端调用WEBService服务

    编写WEBService服务端应用程序并部署 http://blog.csdn.net/u011835515/article/details/47615425 编写调用WEBService的C++客户 ...

  6. MongoDB分片 在部署和维护管理 中常见事项的总结

    分片(sharding)是MongoDB将大型集合分割到不同服务器(或者说集群)上所采用的方法,主要为应对高吞吐量与大数据量的应用场景提供了方法. 和既有的分库分表.分区方案相比,MongoDB的最大 ...

  7. PHP程序污点型漏洞静态检测方法

    这篇文献,作者针对基于PHP语言开发的web应用程序产生的污点型漏洞,提出了一种静态代码分析检测的方法.       先解释一下什么叫污点型漏洞,由于对于用户的输入没有进行有效的过滤,使其进入敏感函数 ...

  8. LeetCode算法题-Maximum Average Subarray I(Java实现)

    这是悦乐书的第278次更新,第294篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第146题(顺位题号是643).给定由n个整数组成的数组,找到具有最大平均值的长度为k的 ...

  9. LeetCode算法题-Max Consecutive Ones(Java实现)

    这是悦乐书的第242次更新,第255篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第109题(顺位题号是485).给定二进制数组,找到此数组中连续1的最大数量.例如: 输 ...

  10. Python 函数初识 (1)

    一.今日主要内容 认识函数 函数:对功能或者动作的封装(定义) 语法: def 函数名字(形参) 函数体 函数的调用格式:函数名(实参) 函数的返回值 关键字:return 终止函数的运行 1.函数内 ...