模板http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html

完全理解以后,我发现这种写法实在是太厉害了,简洁,优美,可以回避很多细节问题,而这些细节如果用递推的方法写,处理起来可能会非常痛苦

http://acm.hdu.edu.cn/showproblem.php?pid=2089

不要62

http://www.cnblogs.com/xiaohongmao/p/3473599.html

前几天写过这道题的解题报告,两种解法都有

http://acm.hdu.edu.cn/showproblem.php?pid=3555

不要49

#include <iostream>
using namespace std ;
typedef __int64 ll ;
ll dp[25][2] ;
int digit[25] ;
ll dfs(int i,int s,bool e)
{
    if(!i)return 1 ;
    if(!e && dp[i][s]!=-1)
        return dp[i][s] ;
    ll res=0 ;
    int u=e?digit[i]:9 ;
    for(int d=0 ;d<=u ;d++)
    {
        if(s && d==9)
            continue ;
        res+=dfs(i-1,d==4,e&&d==u) ;
    }
    return e?res:dp[i][s]=res ;
}
int callen(ll n)
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(ll n,int len)
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
ll solve(ll n)
{
    int len=callen(n) ;
    caldigit(n,len) ;
    return dfs(len,0,1) ;
}
int main()
{ 
    int t ;
    scanf("%d",&t) ;
    memset(dp,-1,sizeof(dp)) ;
    while(t--)
    {
        ll n ;
        scanf("%I64d",&n) ;
        printf("%I64d\n",n+1-solve(n)) ;
    }
    return 0 ;
}
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=3652

出现13且是13的倍数

#include <iostream>
using namespace std ;
int dp[15][15][2][15] ;//当前位数 被13除的余数 是否包括13 最末一位数 
int digit[15] ;
int dfs(int i,int re,bool flag,int last,bool e)
{
    if(!i)return !re && flag ;
    if(!e && dp[i][re][flag][last]!=-1)
        return dp[i][re][flag][last] ;
    int res=0 ;
    int u=e?digit[i]:9 ;
    for(int d=0 ;d<=u ;d++)
        res+=dfs(i-1,(re*10+d)%13,flag || (last==1 && d==3),d,e && d==u) ;
    return e?res:dp[i][re][flag][last]=res ;
}
int callen(int n)
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(int n,int len)
{
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
int solve(int n)
{
    int len=callen(n) ;
    caldigit(n,len) ;
    return dfs(len,0,0,0,1) ;
}
int main()
{
    int n ;
    memset(dp,-1,sizeof(dp)) ;
    while(~scanf("%d",&n))
    {
        printf("%d\n",solve(n)) ;
    }
    return 0 ;
}
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=4389

和上一题很像,要求x整除f(x),由于f(x)范围较小,枚举f(x)就好,注意的地方是有点卡内存,数组要开的比较合适才能过,习惯性开大点会MLE

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
int digit[11] ;
int dp[11][84][84][84] ;
int w ;
int dfs(int i,int s,int mod,int e)
{
    if(!i)return !mod && s==w ;
    if(!e && dp[i][s][mod][w]!=-1)return dp[i][s][mod][w] ;
    int u=e?digit[i]:9 ;
    int res=0 ;
    for(int d=0 ;d<=u ;d++)
        res+=dfs(i-1,s+d,(mod*10+d)%w,e && d==u) ;
    return e?res:dp[i][s][mod][w]=res ;
}
int callen(int n)
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(int n,int len)
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
int solve(int n)
{
    int len=callen(n) ;
    caldigit(n,len) ;
    int ans=0 ;
    for(w=1 ;w<84 ;w++)
        ans+=dfs(len,0,0,1) ;
    return ans ;
}
int main()
{
    memset(dp,-1,sizeof(dp)) ;
    int t ;
    scanf("%d",&t) ;
    for(int cas=1 ;cas<=t ;cas++)
    {
        int l,r ;
        scanf("%d%d",&l,&r) ;
        printf("Case %d: %d\n",cas,solve(r)-solve(l-1)) ;
    }
    return 0 ;
}
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=3709

枚举平衡位置

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
typedef __int64 ll ;
int digit[25] ;
ll dp[25][25][1500] ;
int w ;
ll dfs(int i,int s,int e)
{
    if(!i)return !s ;
    if(!e && dp[i][w][s]!=-1)return dp[i][w][s] ;
    int u=e?digit[i]:9 ;
    ll res=0 ;
    for(int d=0 ;d<=u ;d++)
        res+=dfs(i-1,s+d*(i-w),e && d==u) ;
    return e?res:dp[i][w][s]=res ;
}
int callen(ll n)
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(ll n,int len)
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
ll solve(ll n)
{
    int len=callen(n) ;
    caldigit(n,len) ;
    ll ans=0 ;
    for(w=1 ;w<=len ;w++)
        ans+=dfs(len,0,1) ;
    return ans-len+1 ;
}
int main()
{
    memset(dp,-1,sizeof(dp)) ;
    int t ;
    scanf("%d",&t) ;
    while(t--)
    {
        ll l,r ;
        scanf("%I64d%I64d",&l,&r) ;
        printf("%I64d\n",solve(r)-solve(l-1)) ;
    }
    return 0 ;
}
View Code

 http://acm.hdu.edu.cn/showproblem.php?pid=4722

和4389一样,不过除数只有10一个,更简单

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
typedef __int64 ll ;
int digit[25] ;
ll dp[25][105][15] ;
ll dfs(int i,int s,int mod,int e)
{
    if(!i)return !mod ;
    if(!e && dp[i][s][mod]!=-1)return dp[i][s][mod] ;
    int u=e?digit[i]:9 ;
    ll res=0 ;
    for(int d=0 ;d<=u ;d++)
        res+=dfs(i-1,s+d,(mod+d)%10,e && d==u) ;
    return e?res:dp[i][s][mod]=res ;
}
int callen(ll n)
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(ll n,int len)
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
ll solve(ll n)
{
    int len=callen(n) ;
    caldigit(n,len) ;
    return dfs(len,0,0,1) ;
}
int main()
{
    memset(dp,-1,sizeof(dp)) ;
    int t ;
    scanf("%d",&t) ;
    for(int cas=1 ;cas<=t ;cas++)
    {
        ll l,r ;
        scanf("%I64d%I64d",&l,&r) ;
        printf("Case #%d: %I64d\n",cas,solve(r)-solve(l-1)) ;
    }
    return 0 ;
}
View Code