「数位动规练习」准考证
escription
蒟蒻hzwer NOIP2014惨跪,他依稀记得他的准考证号是37,现在hzwer又将要面临一场比赛,他希望准考证号不出现37(连续),同时他又十分讨厌4,所以也不希望4出现在准考证号中。。。现在他想知道在A和B之间有多少合法的准考证号
Input
包含两个整数,A B
Output
一个整数。
Sample Input
「输入样例一」
1 10
「输入样例二」
25 50
Sample Output
「输出样例一」
9
「输出样例二」
14
「数据规模和约定」
20%的数据,满足 1 <= A <= B <= 1000000 。
100%的数据,满足 1 <= A <= B <= 2000000000 。
题解
f(i,j)表示长度i,开头为j的合法方案
则f(i,j)= ∑ f(i-1,k) (k≠4,j≠4,k≠7 or j≠3)
套数位dp模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<cstring> #define inf 2000000000 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int base[15]; int l,r; int f[15][10]; void pre() { for(int i=0;i<=9;i++) if(i!=4)f[1][i]=1; for(int i=2;i<=10;i++) for(int j=0;j<=9;j++) for(int k=0;k<=9;k++) if(j!=4&&k!=4&&(j!=3||k!=7)) f[i][j]+=f[i-1][k]; } int dp(int x) { if(!x)return 0; int ans=0; int pre=0,cur,L=10; while(base[L]>x)L--; for(int i=1;i<L;i++) for(int j=1;j<=9;j++) ans=ans+f[i][j]; cur=x/base[L];x%=base[L]; if(L==1) for(int i=1;i<=cur;i++) ans=ans+f[L][i]; else for(int i=1;i<cur;i++) ans=ans+f[L][i]; pre=cur; for(int i=L-1;i;i--) { if(cur==4)continue; cur=x/base[i];x%=base[i]; if(i==1) { for(int t=0;t<=cur;t++) if(pre!=3||t!=7) ans+=f[i][t]; } else { for(int t=0;t<cur;t++) if(pre!=3||t!=7) ans+=f[i][t]; } if(pre==3&&cur==7)break; pre=cur; } return ans; } int main() { base[1]=1;for(int i=2;i<=10;i++)base[i]=base[i-1]*10; pre(); scanf("%d%d",&l,&r); printf("%d\n",dp(r)-dp(l-1)); return 0; } |
Subscribe