[数位DP]JZOJ 3363 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。

分析

搞一波类似于容斥的东西,然后把不合法全部枚举出来,在转移过程中如果与不合法匹配则直接归0

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int w[10][2]={{0,0},{3,3},{4,4},{5,5},{7,3},{7,4},{8,3},{8,4},{11,3},{11,4}};
int pow[11]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
int ways[100001][101];
long long f[12][100001],ans;
int a[101][2];
int n;

int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) {
        char s[6];
        scanf("%s",s+1);
        a[i][0]=strlen(s+1);
        for (int j=a[i][0];j;j--) a[i][1]=a[i][1]*10+s[j]-'0';
    }
    for (int i=1;i<=n;i++)
        for (int j=0;j<=99999;j++)
            for (int k=1;k<=6-a[i][0];k++)
            if (j%pow[a[i][0]+k-1]/pow[k-1]==a[i][1]) {
                ways[j][++ways[j][0]]=a[i][0]+k-1;
                break;
            }
    f[0][0]=1;
    for (int i=1;i<=11;i++) {
        for (int j=0;j<=99999;j++)
            for (int k=0;k<=9;k++)
            f[i][j%pow[4]*10+k]+=f[i-1][j];
        for (int k=1;k<=9;k++)
        if (w[k][0]==i)
            for (int j=0;j<=99999;j++)
            if (f[i][j])
                for (int l=1;l<=ways[j][0];l++)
                if (ways[j][l]<=w[k][1]) {
                    f[i][j]=0;
                    break;
                }
    }
    for (int i=0;i<=99999;i++) if (i%10==1) ans+=f[11][i];
    printf("%lld",ans);
}
View Code

 

posted @ 2018-08-19 21:24  Vagari  阅读(206)  评论(0编辑  收藏  举报