数位dp

讲解:

http://blog.csdn.net/niuox/article/details/9864199

http://m.blog.csdn.net/article/details?id=52100392

第一题 http://acm.timus.ru/problem.aspx?space=1&num=1057

#include<bits/stdc++.h>
using namespace std;
int f[50][50],g[50];
int cal(int x,int k,int b)
{
    int len=0,res=0;
    while(x) g[++len]=x%b,x/=b;
    for(int i=len;i;i--)
    {
        if(g[i]>1) res+=f[i-1][k]+f[i-1][k-1];
        else if(g[i]==1) res+=f[i-1][k],k--;
        if(k<0) return res;
    }
    return res;
}
int main()
{
    int x,y,k,b;
    for(int i=0;i<33;i++)
    {
        f[i][0]=1;f[i][1]=i;
        for(int j=2;j<=i;j++) f[i][j]=f[i-1][j]+f[i-1][j-1];
    }
    scanf("%d%d%d%d",&x,&y,&k,&b);
    printf("%d\n",cal(y+1,k,b)-cal(x,k,b));
    return 0;
}

第二题 http://www.lydsy.com/JudgeOnline/problem.php?id=1026

#include <iostream>  
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <math.h>  
#include <map>  
#include <queue>  
#include <algorithm>  
using namespace std;  
  
int A[12];  
  
int f[12][10];  
  
//f[i][j]代表长度为i,最高位为j的windy数个数  
void init()  
{  
   memset(f,0,sizeof(f));  
   for(int i=0;i<10;i++) f[1][i] = 1;  
   for(int i=2;i<=10;i++)  
   {  
      for(int j=0;j<10;j++)  
      {  
         for(int k=0;k<10;k++)  
         {  
            if(abs(j-k)>1) f[i][j] += f[i-1][k];  
         }  
      }  
   }  
}  
//(0,a)范围内的windy数个数  
int calc(int a)  
{  
   int m = 0;  
   while(a)  
   {  
      A[m++] = a%10;  
      a/=10;  
   }  
   int ans = 0;  
   //先处理长度小于m的windy数的个数  
   for(int i=1;i<m;i++)  
   {  
      //题目要求不含前导0  
      for(int j=1;j<10;j++)  
      {  
         ans += f[i][j];  
      }  
   }  
   //长度等于m且最高位和原数不同且小于原数的windy数  
   for(int j=1;j<A[m-1];j++) ans += f[m][j];  
   //依次循环将最高位 变为和原数相同  
   for(int i=m-1;i>=1;i--)  
   {  
      for(int j=0;j<A[i-1];j++)  
      {  
         if(abs(j-A[i]) > 1) ans += f[i][j];  
      }  
      if(abs(A[i] - A[i-1])<=1) break;  
   }  
   return ans;  
}  
  
  
int main()  
{  
   #ifndef ONLINE_JUDGE  
      freopen("in.txt","r",stdin);  
   #endif  
   int a,b;  
   init();  
   while(scanf(" %d %d",&a,&b)!=EOF)  
   {  
      int ans = calc(b+1) - calc(a);  
      printf("%d\n",ans );  
   }  
   return 0;  
}  


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

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef long long ll;
ll f[20][2],g[20];
ll dfs(int pos,int pre,int sta,bool limit)
{
    if(pos==-1) return 1;
    if(!limit&&f[pos][sta]!=-1) return f[pos][sta];
    int up=limit?g[pos]:9;
    ll res=0;
    for(int i=0;i<=up;i++)
    {
        if(pre==6&&i==2) continue;
        if(i==4) continue;
        res+=dfs(pos-1,i,i==6,limit&&i==g[pos]);
    }
    if(!limit) f[pos][sta]=res;
    return res;
}
ll cal(ll x)
{
    ll pos=0;
    while(x) g[pos++]=x%10,x/=10;
    return dfs(pos-1,-1,0,1);
}
int main()
{
    ll l,r;
    memset(f,-1,sizeof f);
    while(~scanf("%lld%lld",&l,&r),l|r)
    {
        printf("%lld\n",cal(r)-cal(l-1));
    }
    return 0;
}

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

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef long long ll;
ll f[20][2],g[20];
ll dfs(int pos,int pre,int sta,bool limit)
{
    if(pos==-1) return 1;
    if(!limit&&f[pos][sta]!=-1) return f[pos][sta];
    int up=limit?g[pos]:9;
    ll res=0;
    for(int i=0;i<=up;i++)
    {
        if(pre==4&&i==9) continue;
        res+=dfs(pos-1,i,i==4,limit&&i==g[pos]);
    }
    if(!limit) f[pos][sta]=res;
    return res;
}
ll solve(ll x)
{
    ll pos=0;
    while(x) g[pos++]=x%10,x/=10;
    return dfs(pos-1,-1,0,1);
}
int main()
{
    ll x,t;
    scanf("%lld",&t);
    memset(f,-1,sizeof f);
    while(t--)
    {
        scanf("%lld",&x);
        printf("%lld\n",x+1-solve(x));
    }
    return 0;
}


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

#include<bits/stdc++.h>// http://acm.hdu.edu.cn/showproblem.php?pid=3709
using namespace std;
const int N=1e3+10;
typedef long long ll;
ll f[20][20][2005],g[20];
ll dfs(int pos,int pre,int sum,bool limit)
{
    if(pos<0) return sum==0;
    if(sum<0) return 0;
    if(!limit&&f[pos][pre][sum]!=-1) return f[pos][pre][sum];
    int up=limit?g[pos]:9;
    ll res=0;
    for(int i=0;i<=up;i++)
    {
        res+=dfs(pos-1,pre,sum+i*(pos-pre),limit&&i==g[pos]);
    }
    if(!limit) f[pos][pre][sum]=res;
    return res;
}
ll cal(ll x)
{
    if(x<0) return 0;
    ll len=0,res=0;
    while(x) g[len++]=x%10,x/=10;
    for(int i=0;i<len;i++)
        res+=dfs(len-1,i,0,1);
    return res-len+1;//排除掉0,00,000....这些情况
}
int main()
{
    ll x,y,t;
    scanf("%lld",&t);
    memset(f,-1,sizeof f);
    while(t--)
    {
        scanf("%lld%lld",&x,&y);
        printf("%lld\n",cal(y)-cal(x-1));
    }
    return 0;
}


第六题 http://acm.hit.edu.cn/hoj/problem/view?id=1983
#include<bits/stdc++.h>// http://acm.hit.edu.cn/hoj/problem/view?id=1983
using namespace std;
const int N=1e3+10;
typedef long long ll;
ll f[20][2525][55],g[20],ha[2525];
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
ll dfs(int pos,int mod,int lcm,bool limit)
{
    if(pos<0) return mod%lcm==0;
    if(!limit&&f[pos][mod][ha[lcm]]!=-1) return f[pos][mod][ha[lcm]];
    int up=limit?g[pos]:9;
    ll res=0;
    for(int i=0;i<=up;i++)
    {
        res+=dfs(pos-1,(mod*10+i)%2520,i?(i*lcm/gcd(i,lcm)):lcm,limit&&i==g[pos]);
    }
    if(!limit) f[pos][mod][ha[lcm]]=res;
    return res;
}
ll cal(ll x)
{
    if(x<0) return 0;
    ll len=0;
    while(x) g[len++]=x%10,x/=10;
    return dfs(len-1,0,1,1);
}
int main()
{
    ll x,y,t;
    memset(f,-1,sizeof f);
    int id=0;
    for(int i=1;i*i<2520;i++)
    if(2500%i==0)
    {
        ha[i]=id++;
        if(i*i!=2520) ha[2520/i]=id++;
    }
    while(~scanf("%lld%lld",&x,&y))
    {
        printf("%lld\n",cal(y)-cal(x-1));
    }
    return 0;
}

第七题 http://acm.hdu.edu.cn/showproblem.php?pid=4507

#include<bits/stdc++.h>// http://acm.hdu.edu.cn/showproblem.php?pid=4507
using namespace std;
const int N=1e3+10;
const int p=1e9+7;
typedef long long ll;
struct node
{
    ll n,s,sq;
}f[20][10][10];
ll g[20],pw[2525];
node dfs(int pos,int mod,int sum,bool limit)
{
    if(pos<0)
    {
        node tmp;
        tmp.n=(mod!=0&&sum!=0);
        tmp.s=tmp.sq=0;
        return tmp;
    }
    if(!limit&&f[pos][mod][sum].n!=-1)  return f[pos][mod][sum];
    int up=limit?g[pos]:9;
    node res,tmp;
    res.n = res.s = res.sq = 0;
    for(int i=0;i<=up;i++)
    {
        if(i==7) continue;
        tmp=dfs(pos-1,(mod*10+i)%7,(sum+i)%7,limit&&i==g[pos]);
        res.n=(res.n+tmp.n)%p;
        res.s=(res.s+tmp.s+((i * pw[pos])%p * tmp.n) % p) % p ;
        res.sq=(res.sq+tmp.sq+((2*i*pw[pos])%p*tmp.s)%p +
                (((i*i*pw[pos])%p*pw[pos])%p*tmp.n)%p)%p;
    }
    if(!limit) f[pos][mod][sum]=res;
    return res;
}
ll cal(ll x)
{
    if(x<0) return 0;
    ll len=0;
    while(x) g[len++]=x%10,x/=10;
    return dfs(len-1,0,0,1).sq;
}
int main()
{
    ll x,y,t;
    memset(f,-1,sizeof f);
    pw[0]=1;
    for(int i=1;i<=19;i++)
    {
        pw[i]=(pw[i-1]*10)%p;
    }
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&x,&y);
        printf("%lld\n",(cal(y)-cal(x-1)+p)%p);
    }
    return 0;
}

第八题 https://www.bnuoj.com/v3/problem_show.php?pid=52325   (他的oj现在好像过不去了)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//位数  数字 关系
ll f[20][10][5],sum[20],g[20];
ll dfs(ll pos,ll num,ll lis,ll flag)
{
	if(pos<=0) return 1;
	if(f[pos][num][lis]!=-1&&!flag) return f[pos][num][lis];
	ll x=flag?g[pos]:9;
	ll res=0;
	for(ll i=0;i<=x;i++)
	{
		if(i<=num&&lis==0)  res+=dfs(pos-1,i,0,flag&&(i==x));
		if(i==num&&lis==1)  res+=dfs(pos-1,i,1,flag&&(i==x));
		if(i>=num&&lis==2)  res+=dfs(pos-1,i,2,flag&&(i==x));
	}
	if(!flag) f[pos][num][lis]=res;
	return res;
}
ll solve(ll x)
{
	ll res=0,pos=0;
	memset(g,0,sizeof g);
	while(x)
	{
		g[++pos]=x%10;
		x/=10;
	}
	pos--;  x=g[pos+1];
	for(ll i=1;i<x;i++)
		res+=dfs(pos,i,0,0)+dfs(pos,i,2,0)-dfs(pos,i,1,0);
	res+=dfs(pos,x,0,1)+dfs(pos,x,2,1)-dfs(pos,x,1,1);
	return res+sum[pos];
}
int main()
{
	ll t,tt=0,x=0,y,z;
	memset(f,-1,sizeof f);
	for(ll i=1;i<20;i++)
	{
		x=x*10+9;
		sum[i]=solve(x);
	}
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld",&x,&y);
		printf("%lld\n",solve(y)-solve(x-1));
	}
}


第九题 http://gdutcode.sinaapp.com/problem.php?cid=1057&pid=6

#include<bits/stdc++.h>
using namespace std;
const int N=20000+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll f[20][20][10][2][2][2],g[20],num[20];
//代表当前第 位上一位是什么,增过,减过,            长度为 len   回文?
ll rec(int pos,int pre,int up,int down,int flag,int q,int len,int ispa)
{
    if(pos<0) return up&&down&&ispa;
    if(~f[pos][len][pre][up][down][ispa]&&!flag&&!q)
    return f[pos][len][pre][up][down][ispa];
    ll x=flag?g[pos]:9;
    ll res=0;
    for(int i=0;i<=x;i++)
    {
        num[pos]=i;
        if(q) res+=rec(pos-1,i,0,0,i<x?0:flag,q&&i==0,len-(q&&i==0),ispa);
        else if(i==pre)
        {
            if(ispa&&pos<len/2)
            res+=rec(pos-1,i,up,down,i<x?0:flag,q&&i==0,len,i==num[len-pos-1]);
            else res+=rec(pos-1,i,up,down,i<x?0:flag,q&&i==0,len,ispa);
        }
        else if(i>pre)
        {
            if(!down) continue;
            if(ispa&&pos<len/2)
            res+=rec(pos-1,i,1,down,i<x?0:flag,q&&i==0,len,i==num[len-pos-1]);
            else res+=rec(pos-1,i,1,down,i<x?0:flag,q&&i==0,len,ispa);
        }
        else if(i<pre)
        {
            if(up) continue;
            if(ispa&&pos<len/2)
            res+=rec(pos-1,i,up,1,i<x?0:flag,q&&i==0,len,i==num[len-pos-1]);
            else res+=rec(pos-1,i,up,1,i<x?0:flag,q&&i==0,len,ispa);
        }
    }
    if(!flag&&!q) f[pos][len][pre][up][down][ispa]=res;
    return res;
}
ll cal(ll x)
{
    int len=0;
    while(x) g[len++]=x%10,x/=10;
    return rec(len-1,0,0,0,1,1,len,1);
}
int main()
{
    ll t,l,r;
    memset(f,-1,sizeof f);
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",cal(r)-cal(l-1));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值