数位dp

1.[hdu3709]Balanced Number

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<ctime>
 8 #include<cmath>
 9 #include<queue>
10 #include<map>
11 #include<set>
12 using namespace std;
13 #define FILE "dealing"
14 #define LL long long
15 #define up(i,j,n) for(LL i=(j);(i)<=(n);i++)
16 #define pii pair< LL , LL >
17 #define abs(x) ((x)<0?-(x):(x))
18 #define max(x,y) ((x)>(y)?(x):(y))
19 #define min(x,y) ((x)<(y)?(x):(y))
20 namespace IO{
21     char buf[1<<15],*fs,*ft;
22     LL gc(){return fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft),fs==ft?-1:*fs++;}
23     LL read(){
24         LL x=0,ch=gc(),f=0;
25         while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=gc();}
26         while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=gc();}
27         return f?-x:x;
28     }
29 }using namespace IO;
30 bool chkmin(LL &a,LL b){return a>b?a=b,true:false;}
31 bool chkmax(LL &a,LL b){return a<b?a=b,true:false;}
32 const LL maxn(1000500),inf(100000000);
33 LL f[20][20][2500],now[20];
34 LL dfs(LL pos,LL pivot,LL ans,LL limit){
35     if(pos<1)return ans == 0;
36     if(ans<0)return 0;
37     if(!limit&&f[pos][pivot][ans]!=-1)return f[pos][pivot][ans];
38     LL len=limit?now[pos]:9;
39     LL ret=0;
40     up(i,0,len)ret+=dfs(pos-1,pivot,ans+(pos-pivot)*i,limit&&i==len);
41     if(!limit)f[pos][pivot][ans]=ret;
42     return ret;
43 }
44 LL slove(LL x){
45     now[0]=0;
46     while(x){now[++now[0]]=x%10;x/=10;}
47     LL ret=0;
48     up(i,1,now[0])ret+=dfs(now[0],i,0,1);
49     return ret-now[0]+1;
50 }
51 int main(){
52     //freopen(FILE".in","r",stdin);
53     //freopen(FILE".out","w",stdout);
54     LL A,B;
55     LL T;
56     T=read();
57     memset(f,-1,sizeof(f));
58     while(T--){
59         A=read();B=read();
60         if(A==0)cout<<slove(B)<<endl;
61         else cout<<slove(B)-slove(A-1)<<endl;
62     }
63     return 0;
64 }

记忆化搜索

2,[hdu3555]只要49

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<ctime>
 8 #include<cmath>
 9 #include<queue>
10 #include<map>
11 #include<set>
12 using namespace std;
13 #define FILE "dealing"
14 #define LL long long
15 #define up(i,j,n) for(LL i=(j);(i)<=(n);i++)
16 #define pii pair< LL , LL >
17 #define abs(x) ((x)<0?-(x):(x))
18 #define max(x,y) ((x)>(y)?(x):(y))
19 #define min(x,y) ((x)<(y)?(x):(y))
20 namespace IO{
21     char buf[1<<15],*fs,*ft;
22     LL gc(){return fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft),fs==ft?-1:*fs++;}
23     LL read(){
24         LL x=0,ch=gc(),f=0;
25         while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=gc();}
26         while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=gc();}
27         return f?-x:x;
28     }
29 }using namespace IO;
30 bool chkmin(LL &a,LL b){return a>b?a=b,true:false;}
31 bool chkmax(LL &a,LL b){return a<b?a=b,true:false;}
32 const LL maxn(1000500),inf(100000000);
33 LL f[50][10];
34 void init(){
35     up(i,0,9)f[1][i]=1;
36     up(i,2,20)up(j,0,9){
37         up(k,0,9){
38             if(j==4&&k==9)continue;
39             f[i][j]+=f[i-1][k];
40         }
41     }
42 }
43 LL slove(LL x){
44     LL now[21],ans=0,flag=0,y=x;
45     now[0]=0;
46     while(x){now[++now[0]]=x%10;x/=10;}
47     up(i,1,now[0]-1)up(j,1,9)ans+=f[i][j];
48     up(i,1,now[now[0]]-1)ans+=f[now[0]][i];
49     LL pre=now[now[0]];
50     for(LL i=now[0]-1;i>=1;i--){
51         if(now[i]==9&&now[i+1]==4)flag=1;
52         up(j,0,now[i]-1){
53             if(now[i+1]==4&&j==9)continue;
54             ans+=f[i][j];
55         }
56         if((now[i]==9&&now[i+1]==4))break;
57         pre=now[i];
58     }
59     if(!flag&&y)ans++;
60     return ans;
61 }
62 int main(){
63     //freopen(FILE".in","r",stdin);
64     //freopen(FILE".out","w",stdout);
65     init();LL A,B;
66     LL T;
67     T=read();
68     while(T--){
69         A=read();
70         cout<<A-slove(A)<<endl;
71     }
72     return 0;
73 }

递推

3.[hdu2089]不要62

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<ctime>
 8 #include<cmath>
 9 #include<queue>
10 #include<map>
11 #include<set>
12 using namespace std;
13 #define FILE "dealing"
14 #define LL long long
15 #define up(i,j,n) for(int i=(j);(i)<=(n);i++)
16 #define pii pair< int , int >
17 #define abs(x) ((x)<0?-(x):(x))
18 #define max(x,y) ((x)>(y)?(x):(y))
19 #define min(x,y) ((x)<(y)?(x):(y))
20 namespace IO{
21     char buf[1<<15],*fs,*ft;
22     int gc(){return fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft),fs==ft?-1:*fs++;}
23     int read(){
24         int x=0,ch=gc(),f=0;
25         while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=gc();}
26         while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=gc();}
27         return f?-x:x;
28     }
29 }using namespace IO;
30 bool chkmin(int &a,int b){return a>b?a=b,true:false;}
31 bool chkmax(int &a,int b){return a<b?a=b,true:false;}
32 const int maxn(1000500),inf(100000000);
33 int f[50][10];
34 void init(){
35     up(i,0,9)f[1][i]=1;f[1][4]=0;
36     up(i,2,10)up(j,0,9){
37         if(j==4)continue;
38         up(k,0,9){
39             if(j==6&&k==2)continue;
40             f[i][j]+=f[i-1][k];
41         }
42     }
43 }
44 int slove(int x){
45     int now[11],ans=0,flag=0;
46     now[0]=0;
47     if(x==0)return 0;
48     while(x){now[++now[0]]=x%10;x/=10;}
49     up(i,1,now[0]-1)up(j,1,9)ans+=f[i][j];
50     up(i,1,now[now[0]]-1)ans+=f[now[0]][i];
51     int pre=now[now[0]];
52     if(pre==4)return ans;
53     for(int i=now[0]-1;i>=1;i--){
54         if(now[i]==4||(now[i]==2&&now[i+1]==6))flag=1;
55         up(j,0,now[i]-1){
56             if(now[i+1]==6&&j==2)continue;
57             ans+=f[i][j];
58         }
59         if((now[i]==2&&now[i+1]==6)||now[i]==4)break;
60         pre=now[i];
61     }
62     if(!flag)ans++;
63     return ans;
64 }
65 int main(){
66     //freopen(FILE".in","r",stdin);
67     //freopen(FILE".out","w",stdout);
68     init();int A,B;
69     while(1){
70         A=read(),B=read();
71         if(A==0&&B==0)return 0;
72         printf("%d\n",slove(B)-slove(A-1));
73     }
74     return 0;
75 }

递推

4.[haoi2010]计数

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<ctime>
 7 #include<iomanip>
 8 #include<queue>
 9 #include<map>
10 #include<set>
11 #include<algorithm>
12 using namespace std;
13 #define FILE "dealing"
14 #define LL long long
15 #define up(i,j,n) for(int i=(j);i<=(n);i++)
16 void chkmin(int &a,int b){a>b?a=b:0;}
17 void chkmax(int &a,int b){a<b?a=b:0;}
18 namespace IO{
19     char buf[1<<15],*fs,*ft;
20     int gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1<<15,1,stdin),fs==ft))?-1:*fs++;}
21     int read(){
22         int x=0,f=0,ch=gc();
23         while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=gc();}
24         while(ch>=‘0‘&&ch<=‘9‘){x=(x<<1)+(x<<3)+ch-‘0‘;ch=gc();}
25         return f?-x:x;
26     }
27 }using namespace IO;
28 const int maxn=52;
29 char s[maxn];
30 int a[10],len;
31 LL fac[30],c[maxn][maxn];
32 int main(){
33     freopen(FILE".in","r",stdin);
34     freopen(FILE".out","w",stdout);
35     c[0][0]=1;
36     for(int i=1;i<=50;i++){
37         c[i][0]=1;
38         for(int j=1;j<=50;j++)c[i][j]=c[i-1][j-1]+c[i-1][j];
39     }
40     scanf("%s",s+1);
41     len=strlen(s+1);
42     up(i,1,len)a[s[i]-‘0‘]++;
43     LL ans=0;
44     for(int i=1;i<=len;i++){
45         for(int j=0;j<s[i]-‘0‘;j++){
46             if(!a[j])continue;
47             a[j]--;
48             int now=len-i;
49             LL sum=1;
50             for(int k=0;k<=9;k++)
51                 sum*=c[now][a[k]],now-=a[k];
52             ans+=sum;
53             a[j]++;
54         }
55         a[s[i]-‘0‘]--;
56     }
57     cout<<ans<<endl;
58     return 0;
59 }

递推

通过这几道题的练习,对数位dp有了些理解;

数位dp的核心是按位确定,这些题无论约束条件如何,但本质不变;

有的约束条件用递推可以解决,于是可以预处理,有的约束条件比较复杂,需要记忆化;

数位dp也体现了dp的本质,每个数位其实就是一个阶段,每次搜索即将发散的时候,下面都有一个状态的承接,不至于时间爆炸;

时间: 2024-08-02 02:51:09

数位dp的相关文章

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

51nod1043(数位dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1043 题意:中文题诶- 思路:数位dp 我们用dp[i][j]来存储长度为2*i且一半和为j的所有情况(包括前导0的情况),为了方便我们现在只讨论其一半的和的情况,因为如果包括前导0的话其两边的情况是一样的: 我们假设再长度为i-1的数字最前面加1位数字k,0<=k<=9(这位数字加在哪里并不影响答案,因为我们在计算i-1长度的时候已经计算了所有组合情况,

【HDU 3652】 B-number (数位DP)

B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task

hdu 5898 odd-even number 数位DP

odd-even number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 716    Accepted Submission(s): 385 Problem Description For a number,if the length of continuous odd digits is even and the length

LightOJ1068 Investigation(数位DP)

这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数 然后就是转移方程,最后就是统计.. 统计部分好棘手...半乱搞下AC的..还是对数位DP的这一部分太不熟悉了. 1 #include<cstdio> 2 #include<cstr

HDU 4734 F(x)(数位DP)

Description For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there betwe

hdu 4734 数位dp

http://acm.hdu.edu.cn/showproblem.php?pid=4734 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, plea

【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)

题意: 多组数据,每组求第n个包含'666'的数(不能断开),如1:666,2:1666,14:6667. 题解: AC自动机解法没去想,数位DP没学,这里有一种类似于数位DP,却又与数位DP不同,我称为数位树. 数位树: 将数n如线段树一样地拆分成多个小段,进行递归处理得出答案. 本题详(lue)解: 直接看每一位应该是什么数,然后n减去相应的数,使得在下一层转换为子问题"在开头有b个连续的6时,求第a个带'666'的数".就是如此简单,如此简单!!!! 代码来啦! #include