可暴力,可dp。
参考资料:Click Me~~
第二个版本的代码参考资料:7k+ 的板子
第二个版本代码在下面
做这道题的时候有两个疑问
第一:既然在dp中 51 既可以看做 51 也可以看做 0051 或者 000051 ,那么51这个数字会不会计算多次。
第二:既然状态转移保证了数字的合法,在统计的时候是否还要继续判断。
首先 dp 的意义 dp[i][j] 表示 i 长度 开头为 j 的数字的数量
关于第一个疑问。在dp中 0051 当然是在dp[3][0] dp[4][0] .. 中各计算一次。
但是我们统计的时候只统计了一次。
统计是这样的,我们只统计比 n 小的数字,先找最高位比 n 小的数字,比如 n=160, 051 这个数字最高位就小于他了,我们统计了一次,当我们统计到第2位的时候,这个意义是在最高位相同的情况下,这一位比 160 小的数字, 这样,我们统计的就是 151 这个数字,而不是051了,当然,每个数字都只统计了一次。
第二:dp[i][j] 只保证 j 开头 长度为i 的数字合法,不保证长度比他大的依然合法。。当然要判断一下。
#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include <set>
#include <stack>
using namespace std;
#define READ freopen("acm.in","r",stdin)
#define WRITE freopen("acm.out","w",stdout)
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define PDI pair<double,int>
#define PDD pair<double,double>
#define MII map<int,int>::iterator
#define fst first
#define sec second
#define MS(x,d) memset(x,d,sizeof(x))
#define INF 0x3f3f3f3f
#define ALL(x) x.begin(),x.end()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ROOT 0,n-1,1
#define PB push_back
#define FOR(a,b,c) for(int a=b;a<c;a++)
#define MOD 10007
#define keyTree (ch[ ch[root][1] ][0])
#define MAX 111
int dp[MAX][MAX];
int solve(int a)
{
int len=0;
int num[20];
MS(num,0);
while(a)
{
num[++len]=a%10;
a/=10;
}
int ans=0;
for(int i=len;i;i--)
{
for(int j=0;j<num[i];j++)
{
if(!(num[i+1]==6&&j==2))
ans+=dp[i][j];
}
if(num[i+1]==6&&num[i]==2)
return ans;
if(num[i]==4)
return ans;
}
return ans;
}
int main()
{
dp[0][0]=1;
for(int i=1;i<=8;i++)
{
for(int j=0;j<=9;j++)// i wei kai tou
{
for(int k=0;k<=9;k++)// i-1 wei kaitou
{
if(j!=4&&(!(j==6&&k==2)))
dp[i][j]+=dp[i-1][k];
}
}
}
int l,r;
while(cin>>l>>r&&l&&r)
{
cout<<solve(r+1)-solve(l)<<endl;
}
return 0;
}
这个代码统计的是 <= n 的数字
#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include <set>
#include <stack>
using namespace std;
#define READ freopen("acm.in","r",stdin)
#define WRITE freopen("acm.out","w",stdout)
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define PDI pair<double,int>
#define PDD pair<double,double>
#define MII map<int,int>::iterator
#define fst first
#define sec second
#define MS(x,d) memset(x,d,sizeof(x))
#define INF 0x3f3f3f3f
#define ALL(x) x.begin(),x.end()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ROOT 0,n-1,1
#define PB push_back
#define FOR(a,b,c) for(int a=b;a<c;a++)
#define MOD 10007
#define keyTree (ch[ ch[root][1] ][0])
#define MAX 111
int dp[MAX][MAX];
int digit[MAX];
int len;
// dfs 在当前位是第 i 位(权重)数字为 s 的时候比 digit 小的数字有多少
int dfs(int i,int s,bool e)// i 是当前位 s 是当前位数字 dp[i][s]=sigma(valid dp[i-1][0-9]) e 为前一位是否是上界
{
if(i==0)
return s==0;
if(!e&&dp[i][s]!=-1)
return dp[i][s];
int u=e?digit[i-1]:9;
int res=0;
for(int j=0;j<=u;j++)
{
if(j!=4&&!(s==6&&j==2))
res+=dfs(i-1,j,e&&j==u);
}
return e?res:dp[i][s]=res;
}
int cal(int n)
{
len=0;
MS(digit,0);
while(n)
{
digit[++len]=n%10;
n/=10;
}
return dfs(len+1,0,1);
}
int main()
{
MS(dp,-1);
int l,r;
while(cin>>l>>r&&l&&r)
cout<<cal(r)-cal(l-1)<<endl;
return 0;
}