[数位dp] Jzoj P3363 Number

Description

JYY 来到了一个新的城市,为了和大家保持联系,第一件事就是办理新的手机号。JYY 对号码的要求很高,希望大家都能够顺畅地阅读手机号,因此 JYY 特别研究了地球人的电话号码阅读习惯,有如下重大发现 (请自行代入你们的手机号码):地球人总是按照以下四种方式来朗读电话号码:
1. xxx-xxx-xxxxx 例如 151-958-83019
2. xxx-xxxx-xxxx 例如 151-9588-3019
3. xxxx-xxxx-xxx 例如 1519-5883-019
4. xxxx-xxx-xxxx 例如 1519-588-3019
即便是同一个电话号码,不同的人也会按照自己的习惯去解读,例如有些人会觉得电话号码是151-9588-3019,而有些却坚持 1519-588-3019。
为了让号码显得更上口,JYY 认为有些不吉利的数字串,在报电话号码时永远不应该被完整地读出来,例如,JYY 认为 7456 是不吉利的数字串 (气死我了),那么 13000007456 就是一个不好的号码,因为有人会把这个号码读作 130-000-07456,而在最后一次完整地读出了 7456。然而,13000745600 却不是一个不好的号码,因为无论怎么读,7456 都会被拆分开来。
现在给出 JYY 认为不吉利的数字串,请你计算满足 JYY 要求的电话号码,总共有多少个。具体来说说,一个好的电话号码满足以下要求:
1. 电话号码是以 1 开头的 11 位数字串。
2. 这个号码无论按照之前描述的 4 种读法中的哪个,都不能在任意时刻连续读出不吉利的数字串。
 

Input

输入文件第一行包括一个整数 n,表示 JYY 认为不吉利的数字串的数量。
接下来 n 行,每行一个不超过 5 的数字串,表示一个 JYY 认为不吉利的号码。

Output

输出一行,为满足条件的电话号码总数。
 

Sample Input

1
7456

Sample Output

9996000100
 

Data Constraint

40% 的数据满足 n <= 2。

100% 的数据满足 1 <= n <= 100。

题解

  • 暴力预处理出那些是不合法的情况
  • 在后面dp中,遇到可以被连读也就是预处理出来的情况直接赋0

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 struct edge {int l,v;}a[110];
 7 int n,mi[20],g[12][100000],f[100000][101],p[10][2]={{0,0},{5,5},{4,4},{3,3},{8,3},{8,4},{7,4},{7,3},{11,3},{11,4}};
 8 char s[20];
 9 long long ans;
10 int main()
11 {
12     mi[0]=1; for (int i=1;i<=9;i++) mi[i]=mi[i-1]*10;
13     scanf("%d",&n);
14     for (int i=1;i<=n;i++)
15     {
16         scanf("%s",s+1);
17         a[i].l=strlen(s+1);
18         for (int j=a[i].l;j>=1;j--) a[i].v=a[i].v*10+s[j]-'0';
19     }
20     for (int i=1;i<=n;i++)
21         for (int j=0;j<=99999;j++)
22             for (int k=1;k<=6-a[i].l;k++)
23                 if ((j%mi[a[i].l+k-1])/mi[k-1]==a[i].v)
24                 {
25                     f[j][++f[j][0]]=a[i].l+k-1;
26                     break;
27                 }
28     g[0][0]=1;
29     for (int i=1;i<=11;i++)
30     {
31         for (int j=0;j<=99999;j++)
32             for (int k=0;k<=9;k++)
33                 g[i][j%mi[4]*10+k]+=g[i-1][j];
34         for (int j=1;j<=9;j++)
35             if (p[j][0]==i)
36                 for (int k=0;k<=99999;k++)
37                     if (g[i][k])
38                         for (int z=1;z<=f[k][0];z++)
39                             if (f[k][z]<=p[j][1])
40                             {
41                                 g[i][k]=0;
42                                 break;
43                             }
44     }
45     for (int i=0;i<=99999;i++) if (i%10==1) ans+=g[11][i];
46     printf("%lld",ans);
47 }

猜你喜欢

转载自www.cnblogs.com/Comfortable/p/9502339.html