链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089
题意:统计给定区间内,数位上没有4且连续两位上不存在62的数字个数
思路:从高位到低位扫,遇到 4 直接跳过,遇到 6 改变状态为 1 并判断下一个数字是否为 2
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int dp[20][2],digit[20];
int dfs(int pos,int sta,int lim)
{
if(pos==0) return 1;
if(!lim&&dp[pos][sta]!=-1) return dp[pos][sta];
int up=lim?digit[pos]:9;
int ans=0;
for(int i=0; i<=up; ++i)
{
if(i==4||(sta==1&&i==2)) continue;
ans+=dfs(pos-1,i==6,lim&&i==up);
}
if(!lim) dp[pos][sta]=ans;
return ans;
}
int solve(int n)
{
int cnt=0;
while(n)
{
digit[++cnt]=n%10;
n/=10;
}
return dfs(cnt,0,1);
}
int main()
{
int l,r;
memset(dp,-1,sizeof(dp));
while(scanf("%d%d",&l,&r)&&(l||r))
printf("%d\n",solve(r)-solve(l-1));
return 0;
}
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555
题意:统计给定区间内,数位上连续两位上是49的数字个数
思路:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int t;
ll n,dp[20][3];
int digit[20];
ll dfs(int pos,int sta,bool lim)
{
if(pos==0) return sta==2;
if(!lim&&dp[pos][sta]!=-1) return dp[pos][sta];
int up=lim?digit[pos]:9;
ll ans=0;
for(int i=0; i<=up; ++i)
{
if(sta==2||(sta==1&&i==9))
ans+=dfs(pos-1,2,lim&&i==up);
else if(i==4)
ans+=dfs(pos-1,1,lim&&i==up);
else
ans+=dfs(pos-1,0,lim&&i==up);
}
if(!lim) dp[pos][sta]=ans;
return ans;
}
ll solve(ll n)
{
int cnt=0;
while(n)
{
digit[++cnt]=n%10;
n/=10;
}
return dfs(cnt,0,1);
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
printf("%lld\n",solve(n));
}
return 0;
}
//这是一段错误的统计代码,错在统计了不连续的4和9
if(sta==2||(sta==1&&i==9))
ans+=dfs(pos-1,2,lim&&i==up);
if(sta==1||(sta==0&&i==4))
ans+=dfs(pos-1,1,lim&&i==up);
if(sta==0&&i!=4)
ans+=dfs(pos-1,0,lim&&i==up);
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652
题意:给定一个 n n n 问 [ 1 , n ] [1,n] [1,n] 中,存在连续两位为 13 并且整个数字能够内 13 整除的数字个数
思路:在需要 13 的基础上,记录连续位的和,并对13取模即可。
#include <bits/stdc++.h>
using namespace std;
int n;
int dp[10][3][15],digit[10];
int dfs(int pos,int sta,bool lim,int sum)
{
if(pos==0) return sta==2&&sum%13==0;
if(!lim&&dp[pos][sta][sum]!=-1) return dp[pos][sta][sum];
int up=lim?digit[pos]:9;
int ans=0;
for(int i=0; i<=up; ++i)
{
if(sta==2||(sta==1&&i==3))
ans+=dfs(pos-1,2,lim&&i==up,(sum*10+i)%13);
else if(i==1)
ans+=dfs(pos-1,1,lim&&i==up,(sum*10+i)%13);
else
ans+=dfs(pos-1,0,lim&&i==up,(sum*10+i)%13);
}
if(!lim) dp[pos][sta][sum]=ans;
return ans;
}
int solve(int n)
{
int cnt=0;
while(n)
{
digit[++cnt]=n%10;
n/=10;
}
return dfs(cnt,0,1,0);
}
int main()
{
memset(dp,-1,sizeof(dp));
while(~scanf("%d",&n))
printf("%d\n",solve(n));
return 0;
}
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4389
题意:给定区间 [ l , r ] [l,r] [l,r],询问区间内满足 x % f ( x ) = 0 x \% f(x)=0 x%f(x)=0 的数的个数, f ( x ) f(x) f(x) 是 x x x 各个数位之和。 ( 1 ≤ x ≤ 1 0 9 ) (1\le x\le 10^9) (1≤x≤109)
思路:注意到模数最多只有 81 ,因此可以枚举模数,这样可以使 x 在 dfs 过程中不断取模控制在81以内,从而记忆化。
#include <bits/stdc++.h>
using namespace std;
int t;
int dp[10][85][85][85],digit[10];
int dfs(int pos,int x,int sum,int mod,bool lim)
{
if(pos==0) return sum==mod&&x%mod==0;
if(!lim&&dp[pos][x][sum][mod]!=-1) return dp[pos][x][sum][mod];
int up=lim?digit[pos]:9;
int ans=0;
for(int i=0; i<=up; ++i)
ans+=dfs(pos-1,(x*10+i)%mod,sum+i,mod,lim&&i==up);
if(!lim) dp[pos][x][sum][mod]=ans;
return ans;
}
int solve(int n)
{
int cnt=0;
while(n)
{
digit[++cnt]=n%10;
n/=10;
}
int ans=0;
for(int i=1; i<=81; ++i)
ans+=dfs(cnt,0,0,i,1);
return ans;
}
int main()
{
int Case=0;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
while(t--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("Case %d: %d\n",++Case,solve(r)-solve(l-1));
}
return 0;
}