数位DP专题
2017-05-18 10:46
141 查看
专题链接
链接
有关数位统计问题,无法暴力求解 则在数位上进行递推 [n,m]=[0,m]-[0,n-1] 统计小于<n的合法数字即可
对于任意一个<n的数字x 肯定从高位到低位出现某一位<n的那一位.
则可以从高位到低位枚举 第一次<n的对应位是哪一位,这样之后的位不受n的限制[x00.00]~[x9999] 把不受限制的整体用DP记录
HDU 2089 不要62 (入门)
题意:非法数字为含4或者62的数字,问[n,m]区间内有多少个合法数字,n,m<=1e9
dp[i][0/1] //当前为第i位,前一位是否为6 枚举每一位 合法转移状态即可
ps:dfs暴力枚举的同时 用DP记录相同状态的方法数
HDU 3652 B-number (20)
题意:给出n<=1e9 合法数为包含13&&能被13整除,求[0,n]内合法数的个数
首先整除13->模13为0 所以加上状态模13的余数
dp[i][j][l][1/0] i位数 前一位为pre,除13余数为mod,是否包含13.
枚举当前位 合法转移状态即可
HDU 4734 F(X)
题意:给出A,B<=1e9,定义F(x)=a[n-1]*2^(n-1)+....a[0]*2^0 a[i]为x每位上的数字,问[0,B]内有多少数 <=F(A)
A为给出的,F(A)是变化的 最大不超过1e4 所以设状态,dp[i][y] i位数,权值不大于y的个数
当pos<0返回num>=0 其余按照枚举每位数转移状态即可
POJ 3252 Round Number
题意:给出n,m<=2e9 问[n,m]内有多少个数,其二进制表示中1的个数不多0的个数?
设状态dp[i][x][y] i为二进制 1的个数为x,0的个数为y
注意前导0为缺位,不能加入0的个数中
题意:给出n,m<=2e9 定义合法数为:数x存在一个轴 其左边部分数字*offset[i]==其右边部分数字*offset[i].
offset[i]为第i位数字到轴距离,问[n,m]内合法的数的个数?
设状态dp[i][j][k] i位数字,轴为第j位 左右是否相等 则平衡度为k
枚举轴为第x位时的ans 累加即可
FZU 2109 Mountain Number
题意:合法的数a[0]a[1]..a[len-1]定义为:a[2i+1]>=a[2i]&&a[2i+1]>=a[2i+2],问[l,r]内有多少个数为合法? l,r<=1e9;
奇数位要大于相邻的两个偶数位.i位数 因为前导0原因 第i位可能为偶或者奇数位,所以状态要加上[0/1]
数位DP设dp[i][pre][0/1] i位数,前一位为pre,当前位为偶/奇数位时的合法个数
最高位始终为偶数位,有前导0时,sta=0,前面放9方便判断
P.d
题意:定义数x合法:当x能被自己所有的digit整除,i.e:15能被1和5整除为合法.
l,r<=1e18,问[l,r]内有多少个数合法?
能被自己所有的digit整除 也就是被lcm(d[1]..d[i])整除
lcm(1,2..9)=2520 则设dp[pos][lcm][num] 因为x%2520和x同余任意一个lcm 所以num为当高位到pos位的数%2520 最后判断num%lcm==0是否成立即可
链接
有关数位统计问题,无法暴力求解 则在数位上进行递推 [n,m]=[0,m]-[0,n-1] 统计小于<n的合法数字即可
对于任意一个<n的数字x 肯定从高位到低位出现某一位<n的那一位.
则可以从高位到低位枚举 第一次<n的对应位是哪一位,这样之后的位不受n的限制[x00.00]~[x9999] 把不受限制的整体用DP记录
HDU 2089 不要62 (入门)
题意:非法数字为含4或者62的数字,问[n,m]区间内有多少个合法数字,n,m<=1e9
dp[i][0/1] //当前为第i位,前一位是否为6 枚举每一位 合法转移状态即可
ps:dfs暴力枚举的同时 用DP记录相同状态的方法数
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=2e3+20; int n,m,a ; int dp [2];//dp[i][0/1] //当前为第i位,前一位是否为6 int DP(int pos,int pre,int sta,bool limit)//limit 当前位是否<n的对应位 { if(pos==-1) return 1; if(!limit && dp[pos][sta]!=-1)//后面位任意 return dp[pos][sta]; int up=limit? a[pos]:9; int sum=0; for(int i=0;i<=up;i++) { if(pre==6&&i==2||(i==4)) continue; sum+=DP(pos-1,i,i==6,limit&&(i==a[pos])); } if(!limit) //dp统计是固定位数pos位[000.00,999.99]无限制时的合法个数 dp[pos][sta]=sum; return sum; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } return DP(pos-1,-1,0,true); } int main() { memset(dp,-1,sizeof(dp)); while(cin>>n>>m&&(n+m)) printf("%d\n",solve(m)-solve(n-1)); return 0; }
HDU 3652 B-number (20)
题意:给出n<=1e9 合法数为包含13&&能被13整除,求[0,n]内合法数的个数
首先整除13->模13为0 所以加上状态模13的余数
dp[i][j][l][1/0] i位数 前一位为pre,除13余数为mod,是否包含13.
枚举当前位 合法转移状态即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=20; int n,m,a ; int dp [2]; // i位数 前一位为pre,除13余数为mod,是否包含13. int DP(int pos,int pre,int mod,int sta,bool limit)//limit 当前位是否<n的对应位 { if(pos==-1) return sta&&mod==0;//枚举完毕 返回是否合法 if(!limit&&dp[pos][pre][mod][sta]!=-1) return dp[pos][pre][mod][sta]; int up=limit?a[pos]:9; int sum=0; for(int i=0;i<=up;i++) sum+=DP(pos-1,i,(mod*10+i)%13,sta||(pre==1&&i==3),limit&&(i==a[pos])); if(!limit) dp[pos][pre][mod][sta]=sum; return sum; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } return DP(pos-1,0,0,0,true); } int main() { memset(dp,-1,sizeof(dp)); while(cin>>n) printf("%d\n",solve(n)); return 0; }
HDU 4734 F(X)
题意:给出A,B<=1e9,定义F(x)=a[n-1]*2^(n-1)+....a[0]*2^0 a[i]为x每位上的数字,问[0,B]内有多少数 <=F(A)
A为给出的,F(A)是变化的 最大不超过1e4 所以设状态,dp[i][y] i位数,权值不大于y的个数
当pos<0返回num>=0 其余按照枚举每位数转移状态即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=20; ll A,B,C,a ,pw2 ; int dp [50000];//dp[i][y] i位数,权值不大于y的个数 int DP(int pos,int num,bool limit) { if(pos==-1) return num>=0; if(num<0) return 0; if(!limit&&dp[pos][num]!=-1) return dp[pos][num]; int up=limit?a[pos]:9; int sum=0; for(int i=0;i<=up;i++) sum+=DP(pos-1,num-i*pw2[pos],limit&&(i==a[pos])); if(!limit) dp[pos][num]=sum; return sum; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } return DP(pos-1,C,true); } int main() { pw2[0]=1; for(int i=1;i<=10;i++) pw2[i]=pw2[i-1]*2; int t,cas=0; scanf("%d",&t); memset(dp,-1,sizeof(dp)); while(t--) { scanf("%d%d",&A,&B); C=0; for(int i=0;i<10&&A;i++) C+=pw2[i]*(A%10),A/=10; printf("Case #%d: %d\n",++cas,solve(B)); } return 0; }
POJ 3252 Round Number
题意:给出n,m<=2e9 问[n,m]内有多少个数,其二进制表示中1的个数不多0的个数?
设状态dp[i][x][y] i为二进制 1的个数为x,0的个数为y
注意前导0为缺位,不能加入0的个数中
#include <iostream> #include <vector> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=40; ll n,m,a ; ll dp ; ll DP(int pos,int x,int y,int sta,bool limit) { if(pos<0) return y>=x; if(!limit&&dp[pos][x][y]!=-1) return dp[pos][x][y]; int up=limit?a[pos]:1; ll sum=0; for(int i=0;i<=up;i++) { if(i==0) sum+=DP(pos-1,x,y+sta,sta,limit&&i==a[pos]); if(i==1) sum+=DP(pos-1,x+1,y,1,limit&&i==a[pos]); } if(!limit) dp[pos][x][y]=sum; return sum; } ll solve(ll n) { int pos=0; while(n) { a[pos++]=n%2; n/=2; } return DP(pos-1,0,0,0,true); } int main() { memset(dp,-1,sizeof(dp)); while(cin>>n>>m) printf("%I64d\n",solve(m)-solve(n-1)); return 0; }
题意:给出n,m<=2e9 定义合法数为:数x存在一个轴 其左边部分数字*offset[i]==其右边部分数字*offset[i].
offset[i]为第i位数字到轴距离,问[n,m]内合法的数的个数?
设状态dp[i][j][k] i位数字,轴为第j位 左右是否相等 则平衡度为k
枚举轴为第x位时的ans 累加即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=20; ll dp [2005]; int a ; ll DP(int pos,int piv,int sta,bool limit) { if(pos==0) return sta==0; if(sta<0)//平衡度若为负 则之后都为递减 return 0; if(!limit&&dp[pos][piv][sta]!=-1) return dp[pos][piv][sta]; int up=limit?a[pos]:9; ll sum=0; for(int i=0;i<=up;i++) sum+=DP(pos-1,piv,sta+(pos-piv)*i,limit&&i==up); if(!limit) dp[pos][piv][sta]=sum; return sum; } ll solve(ll n) { int pos=0; while(n) { a[++pos]=n%10; n/=10; } ll sum=0; for(int i=pos;i>=1;i--)//枚举轴 sum+=DP(pos,i,0,true); return sum-pos+1;//除去全部为0的情况 } int main() { memset(dp,-1,sizeof(dp)); ll t,n,m; cin>>t; while(t--) { cin>>n>>m; printf("%I64d\n",solve(m)-solve(n-1)); } return 0; }
FZU 2109 Mountain Number
题意:合法的数a[0]a[1]..a[len-1]定义为:a[2i+1]>=a[2i]&&a[2i+1]>=a[2i+2],问[l,r]内有多少个数为合法? l,r<=1e9;
奇数位要大于相邻的两个偶数位.i位数 因为前导0原因 第i位可能为偶或者奇数位,所以状态要加上[0/1]
数位DP设dp[i][pre][0/1] i位数,前一位为pre,当前位为偶/奇数位时的合法个数
最高位始终为偶数位,有前导0时,sta=0,前面放9方便判断
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; const int N=2e2+20; int n,a ,dp [2]; int DP(int pos,int pre,int sta,int lead,bool limit) { if(pos<0) return 1; if(!limit&&dp[pos][pre][sta]!=-1) return dp[pos][pre][sta]; int up=limit?a[pos]:9; int res=0; for(int i=0;i<=up;i++) { if(lead&&i==0) res+=DP(pos-1,9,0,1,limit&&i==a[pos]);//最高位始终为偶数位,有前导0 前面放9方便判断 else if(sta==0&&i<=pre) res+=DP(pos-1,i,1-sta,0,limit&&i==a[pos]); else if(sta&&i>=pre) res+=DP(pos-1,i,1-sta,0,limit&&i==a[pos]); } if(!limit) dp[pos][pre][sta]=res; return res; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } //最高位开始为偶数位 return DP(pos-1,9,0,1,true); } int main() { memset(dp,-1,sizeof(dp)); int T; cin>>T; while(T--) { int l,r; cin>>l>>r; int ans=solve(r)-solve(l-1); cout<<ans<<endl; } return 0; }
P.d
题意:定义数x合法:当x能被自己所有的digit整除,i.e:15能被1和5整除为合法.
l,r<=1e18,问[l,r]内有多少个数合法?
能被自己所有的digit整除 也就是被lcm(d[1]..d[i])整除
lcm(1,2..9)=2520 则设dp[pos][lcm][num] 因为x%2520和x同余任意一个lcm 所以num为当高位到pos位的数%2520 最后判断num%lcm==0是否成立即可
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2530; ll dp[20][50] ,n,m; int a[20]; int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } int index ; void init() { int cnt=0; for(int i=1;i<=2520;i++) if(2520%i==0) index[i]=cnt++; } ll dfs(int pos,int lcm,int num,bool limit) { if(pos<0) return num%lcm==0; if(!limit&&dp[pos][index[lcm]][num]!=-1) return dp[pos][index[lcm]][num]; ll res=0; int up=limit?a[pos]:9; for(int i=0;i<=up;i++) { int now=lcm; if(i) now=lcm*i/gcd(lcm,i); res+=dfs(pos-1,now,(num*10+i)%2520,limit&&i==a[pos]); } if(!limit) dp[pos][index[lcm]][num]=res; return res; } ll solve(ll n) { int pos=0; while(n) { a[pos++]=n%10; n/=10; } return dfs(pos-1,1,0,true); } int main() { init(); int T; cin>>T; memset(dp,-1,sizeof(dp)); while(T--) { cin>>n>>m; cout<<solve(m)-solve(n-1)<<endl; } return 0; }
相关文章推荐
- 数位dp专题
- acdream 数树专题--完美数(数位dp)
- 数位统计/数位DP 专题
- 数位DP专题
- [kuangbin带你飞]专题十五 数位DP K - Balanced Numbers (数位dp)(进制转换)
- UESTC 884 方老师的专题讲座 --数位DP
- 11/12训练日记 数位dp专题结束
- 数位DP专题(开坑。
- 数位DP专题总结
- 【数位DP】专题
- UESTC 2015dp专题 H 邱老师选妹子 数位dp
- [专题总结]数位DP
- 数位DP专题小结--by sgx
- 专题(弱点)Dp训练总结【状压Dp*1+区间Dp*5+数位dp*3+树型Dp*2】【10/11】
- 数位dp初等专题小总结
- 【专题】数位DP(按位DP)
- [kuangbin带你飞]专题十五 数位DP
- 逊哥dp专题 总结(普通dp,斜率优化dp,数位dp)
- 【专题】数位DP
- 数位dp专题 (HDU 4352 3652 3709 4507 CodeForces 55D POJ 3252)