ID
Origin
Title
  62 / 175 Problem A CodeForces 55D Beautiful numbers
  30 / 84 Problem B HDU 4352 XHXJ's LIS
  108 / 195 Problem C HDU 2089 不要62
  89 / 222 Problem D HDU 3555 Bomb
  59 / 107 Problem E POJ 3252 Round Numbers
  47 / 75 Problem F HDU 3709 Balanced Number
  64 / 95 Problem G HDU 3652 B-number
  42 / 124 Problem H HDU 4734 F(x)
  11 / 20 Problem I ZOJ 3494 BCD Code
  31 / 100 Problem J HDU 4507 吉哥系列故事――恨7不成妻
  42 / 75 Problem K SPOJ BALNUM Balanced Numbers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

62 / 175 Problem A CodeForces 55D Beautiful numbers

一个美丽数就是可以被它的每一位的数字整除的数。

给定一个区间,求美丽数的个数。

这题是很好的数位DP。

比较难想状态。

就是被每一个数字的LCM整除。

1~9的LCM最大是2520,其实也只有48个。

然后dp[i][j][k]表示处理到数位i,该数对2520取模为j,各个数位的LCM为k

  1. /*
  2. * 题意:求区间[x , y]中beautiful number的个数,
  3. * a positive integer number is beautiful if and only
  4. * if it is divisible by each of its nonzero digits.
  5. 分析:一个数能被它的所有非零数位整除,则能被它们的最小公倍数整除,而1到9的最小公倍数为2520,
  6. 数位DP时我们只需保存前面那些位的最小公倍数就可进行状态转移,到边界时就把所有位的lcm求出了,
  7. 为了判断这个数能否被它的所有数位整除,我们还需要这个数的值,显然要记录值是不可能的,其实我们只
  8. 需记录它对2520的模即可,这样我们就可以设计出如下数位DP:dfs(pos,mod,lcm,f),pos为当前
  9. 位,mod为前面那些位对2520的模,lcm为前面那些数位的最小公倍数,f标记前面那些位是否达到上限,
  10. 这样一来dp数组就要开到19*2520*2520,明显超内存了,考虑到最小公倍数是离散的,1-2520中可能
  11. 是最小公倍数的其实只有48个,经过离散化处理后,dp数组的最后一维可以降到48,这样就不会超了。
  12. */
  13.  
  14. #include <iostream>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <algorithm>
  18. using namespace std;
  19. const int MAXN=;
  20. const int MOD=;//1~9的lcm为2520
  21. long long dp[MAXN][MOD][];
  22. int index[MOD+];//记录1~9的最小公倍数
  23. int bit[MAXN];
  24. int gcd(int a,int b)
  25. {
  26. if(b==)return a;
  27. else return gcd(b,a%b);
  28. }
  29. int lcm(int a,int b)
  30. {
  31. return a/gcd(a,b)*b;
  32. }
  33.  
  34. void init()
  35. {
  36. int num=;
  37. for(int i=;i<=MOD;i++)
  38. if(MOD%i==)
  39. index[i]=num++;
  40. }
  41. long long dfs(int pos,int preSum,int preLcm,bool flag)
  42. {
  43. if(pos==-)
  44. return preSum%preLcm==;
  45. if(!flag && dp[pos][preSum][index[preLcm]]!=-)
  46. return dp[pos][preSum][index[preLcm]];
  47. long long ans=;
  48. int end=flag?bit[pos]:;//上界
  49. for(int i=;i<=end;i++)
  50. {
  51. int nowSum=(preSum*+i)%MOD;
  52. int nowLcm=preLcm;
  53. if(i)nowLcm=lcm(nowLcm,i);
  54. ans+=dfs(pos-,nowSum,nowLcm,flag && i==end);
  55. }
  56. if(!flag)dp[pos][preSum][index[preLcm]]=ans;
  57. return ans;
  58. }
  59. long long calc(long long x)
  60. {
  61. int pos=;
  62. while(x)
  63. {
  64. bit[pos++]=x%;
  65. x/=;
  66. }
  67. return dfs(pos-,,,);
  68. }
  69. int main()
  70. {
  71. int T;
  72. long long l,r;
  73. init();
  74. memset(dp,-,sizeof(dp));
  75. scanf("%d",&T);
  76. while(T--)
  77. {
  78. scanf("%I64d%I64d",&l,&r);
  79. printf("%I64d\n",calc(r)-calc(l-));
  80. }
  81. return ;
  82. }

30 / 84 Problem B HDU 4352 XHXJ's LIS

108 / 195 Problem C HDU 2089 不要62

d.求n~m间的数中,多少不带4和62的数。

n、m(0<n≤m<1000000)

s.见注释

  1. #include<iostream>
  2. #include<stdio.h>
  3. using namespace std;
  4.  
  5. long long dp[][];
  6. /*
  7. i位数时,相应情况的数字总数
  8. dp[i][0],不含有不吉利数字
  9. dp[i][1],不含有不吉利数字,最高位为2
  10. dp[i][2],含有不吉利数字
  11. */
  12. void init(){
  13. dp[][]=;
  14. dp[][]=dp[][]=;
  15. int i;
  16. for(i=;i<=;++i){
  17. dp[i][]=*dp[i-][]-dp[i-][];//不含不吉利数字前面加除4外9个数,减掉2前面加6
  18. dp[i][]=dp[i-][];//不含不吉利数字前面加2
  19. dp[i][]=*dp[i-][]+dp[i-][]+dp[i-][];//含不吉利数字前面加0~9,加上不含不吉利数字前加4,加上2前面加6
  20. }
  21. }
  22. int bit[];
  23. int calc(int n){
  24. int len=,i,tmp=n;
  25. while(n){
  26. bit[++len]=n%;
  27. n/=;
  28. }
  29. bit[len+]=;
  30. bool flag=false;//前缀出现4或者62了吗
  31. long long ans=;
  32. for(i=len;i>=;--i){
  33. ans+=dp[i-][]*bit[i];//注意这个位置,求的是前缀+当前位置(0~bit[i]-1正好是bit[i]种,当前位是不能为bit[i]的)
  34. if(flag)ans+=dp[i-][]*bit[i];//此时当前位为0~bit[i]-1时,后面不含不吉利数字的全都不行
  35. else{//有3种情况
  36. if(bit[i]>)ans+=dp[i-][];//这位为4的时候(ps:为什么不是>=4?因为只有>4时才能保证当前位取4时,后面的数全都能取到,下同)
  37. if(bit[i+]==&&bit[i]>)ans+=dp[i][];//上位为6,这位为2的时候
  38. if(bit[i]>)ans+=dp[i-][];//这位为6的时候
  39. }
  40. if(bit[i]==||bit[i+]==&&bit[i]==)flag=true;//前缀出现的4或者62了。
  41. }
  42. if(flag)++ans;//加上n本身,这个数也不行
  43. return tmp-ans;
  44. }
  45.  
  46. int main(){
  47. init();
  48. int n,m;
  49.  
  50. while(scanf("%d%d",&n,&m)){
  51. if(n==&&m==)break;
  52. printf("%d\n",calc(m)-calc(n-));
  53. }
  54. return ;
  55. }

89 / 222 Problem D HDU 3555 Bomb

d.求1到n有多少个数中含有49,1<=n<=2^63-1(2^32是10位,2^64约20位)

s.数位dp,和上个题类似,少了个条件

dp[i][0],长度为i,不含有49的个数
dp[i][1],长度为i,不含有49,最高位为9的个数
dp[i][2],长度为i,含有49的个数

状态转移方程:

dp[i][0]=10*dp[i-1][0]-dp[i-1][1];//不含49的前面加0~9,减掉9前面加4
dp[i][1]=dp[i-1][0];//不含49的前面加9
dp[i][2]=10*dp[i-1][2]+dp[i-1][1];//含49的前面加0~9,加上9前面加4

求解:从最高位开始遍历,每一位求的都是  前缀+小于当前位  的符合条件的个数。

1.首先加上当前位置之后包含49的个数,因为当前为可以填0~bit[i]-1,所以乘以bit[i],ans+=dp[i-1][2]*bit[i];//注意这个位置,求的是前缀+当前位置
2.前面的前缀出现49了,ans+=dp[i-1][0]*bit[i];//
3.前缀没有出现49,并且当前位>4,ans+=dp[i-1][1];

  1. #include<iostream>
  2. #include<stdio.h>
  3. using namespace std;
  4.  
  5. long long dp[][];
  6. /*
  7. dp[i][0],不含有49
  8. dp[i][1],不含有49,最高位为9
  9. dp[i][2],含有49
  10. */
  11. void init(){
  12. dp[][]=;
  13. dp[][]=dp[][]=;
  14. int i;
  15. for(i=;i<;++i){
  16. dp[i][]=*dp[i-][]-dp[i-][];//不含49的前面加0~9,减掉9前面加4
  17. dp[i][]=dp[i-][];//不含49的前面加9
  18. dp[i][]=*dp[i-][]+dp[i-][];//含49的前面加0~9,加上9前面加4
  19. }
  20. }
  21. int bit[];
  22. long long calc(long long n){
  23. int len=,i;
  24. while(n){
  25. bit[++len]=n%;
  26. n/=;
  27. }
  28. bit[len+]=;
  29. bool flag=false;
  30. long long ans=;
  31. for(i=len;i>=;--i){
  32. ans+=dp[i-][]*bit[i];//注意这个位置,求的是前缀+当前位置
  33. if(flag)ans+=dp[i-][]*bit[i];
  34. else if(bit[i]>)ans+=dp[i-][];
  35. if(bit[i+]==&&bit[i]==)flag=true;
  36. }
  37. if(flag)++ans;//加上n本身
  38. return ans;
  39. }
  40.  
  41. int main(){
  42. init();
  43. int t;
  44. long long n;
  45. scanf("%d",&t);
  46. while(t--){
  47. scanf("%lld",&n);
  48. printf("%I64d\n",calc(n));
  49. }
  50. return ;
  51. }

59 / 107 Problem E POJ 3252 Round Numbers

d.Round Numbers 就是一个表示成二进制的时候0比1多或者相等的正数,注意是正数,所以0就肯定不是了。
题目是给定一个区间,问在这个区间上的Round Numbers有多少个?
首先是求出小于等于n的Round Numbers有多少个。
s.我先举个例子来先说明,再来说一般方法。
比如: 22 = 10110b 如果要求 <=22的Round Numbers,也就是找出1-22有多少个二进制的0不少于1的数的个数。
22的二进制长度是5.
首先找长度比5小的Round Numbers(长度比5小的数肯定小于22啦)
长度为4的话,第一位必须是1,后面三位的话,可以有2个0,3个0
所以就是C(3,2)+C(3,3);
长度为3的Round Numbers,同理有 C(2,2);//注意不要把第一位1忘记了
长度为2的Round Numbers,有 C(1,1)
长度为1的Round Numbers,有 0个
下面是找长度和22相同的Round Numbers。
首先第一位是1.
22的第二位是0,所以第二位不能为1,必须是0
第三位为0的话,(前面有了2个0,1个1),后面两位可以有1个0,2个0
C(2,1)+C(2,2)
接下来把第三位恢复为1,看第四位。假如第四位是0,(前面有2个0,2个1),后面一位必须是0 C(1,1)
所以大致求的过程就如上面所述。

首先先推个公式,就是长度为len的Round Numbers的个数。
长度为len,第一位肯定是1了。
那么后面剩下 len-1位。
如果len-1是偶数。
那么 C(len-1,(len-1)/2+1)+C(len-1,(len-1)/2+2)+````C(len-1,len-1)
= ( 2^(len-1)-C(len-1,(len-1)/2) )/2;
如果len是奇数
那么就是 ( 2^(len-1) )/2
所以上面求比N长度小的Round Numbers是很好求的了。
至于求长度的,则是逐渐把每一位1变为0,去求后面的,就可以保证比n小了。
看代码吧。很容易理解的。

  1. #include<iostream>
  2. #include<stdio.h>
  3. using namespace std;
  4.  
  5. int C[][];
  6. void init(){
  7. C[][]=;
  8. C[][]=;C[][]=;
  9. int i,j;
  10. for(i=;i<;++i){
  11. C[i][]=;
  12. for(j=;j<i;++j){
  13. C[i][j]=C[i-][j-]+C[i-][j];
  14. }
  15. C[i][i]=;
  16. }
  17. }
  18. int bits[];
  19. int calc(int n){////求小于等于n的 Round Numbers
  20. if(n==){//
  21. return ;
  22. }
  23. int len;
  24. len=;
  25. while(n>){
  26. if(n&){
  27. bits[len++]=;
  28. }
  29. else{
  30. bits[len++]=;
  31. }
  32. n>>=;
  33. }
  34. int ans;
  35. ans=;
  36. int i;
  37. //求出长度1~len-1的所有情况
  38. for(i=len-;i>;--i){
  39. if(i&){
  40. ans=ans+((<<(i-))-C[i-][(i-)/])/;
  41. }
  42. else{
  43. ans=ans+(<<(i-))/;
  44. }
  45. }
  46. int cnt0,cnt1;//前缀出现0的个数和1的个数
  47. cnt0=;
  48. cnt1=;
  49. int j;
  50. //长度为len的情况,小于n的
  51. for(i=len-;i>=;--i){
  52. if(bits[i]==){//后面有i位,当前第i位当成0
  53. for(j=i;j>=&&cnt0++j>=cnt1+i-j;--j){//后面i位中选j个0
  54. ans=ans+C[i][j];
  55. }
  56. ++cnt1;
  57. }
  58. else{
  59. ++cnt0;
  60. }
  61. }
  62. //看看原来这个数n
  63. cnt0=;
  64. cnt1=;
  65. for(i=;i<len;++i){
  66. if(bits[i]==){
  67. ++cnt0;
  68. }
  69. else{
  70. ++cnt1;
  71. }
  72. }
  73. if(cnt0>=cnt1){
  74. ++ans;
  75. }
  76. return ans;
  77. }
  78.  
  79. int main(){
  80. init();
  81. int a,b;
  82.  
  83. while(~scanf("%d%d",&a,&b)){
  84. printf("%d\n",calc(b)-calc(a-));
  85. }
  86.  
  87. return ;
  88. }

47 / 75 Problem F HDU 3709 Balanced Number

找出区间内平衡数的个数,所谓的平衡数,就是以这个数字的某一位为支点,另外两边的数字大小乘以力矩之和相等,即为平衡数

  1. /*
  2. * HDU 3709
  3. * 平衡数,枚举支点
  4. * dp[i][j][k] i表示处理到的数位,j是支点,k是力矩和
  5. */
  6.  
  7. #include <iostream>
  8. #include <stdio.h>
  9. #include <algorithm>
  10. #include <string.h>
  11. using namespace std;
  12. long long dp[][][];
  13. int bit[];
  14. long long dfs(int pos,int center,int pre,bool flag)
  15. {
  16. if(pos==-)return pre==;
  17. if(pre<)return ;//当前力矩为负,剪枝
  18. if(!flag&&dp[pos][center][pre]!=-)
  19. return dp[pos][center][pre];
  20. int end=flag?bit[pos]:;
  21. long long ans=;
  22. for(int i=;i<=end;i++)
  23. ans+=dfs(pos-,center,pre+i*(pos-center),flag&&i==end);
  24. if(!flag)dp[pos][center][pre]=ans;
  25. return ans;
  26. }
  27. long long calc(long long n)
  28. {
  29. int len=;
  30. while(n)
  31. {
  32. bit[len++]=n%;
  33. n/=;
  34. }
  35. long long ans=;
  36. for(int i=;i<len;i++)
  37. ans+=dfs(len-,i,,);
  38. return ans-(len-);//去掉全0的情况
  39. }
  40. int main()
  41. {
  42. // freopen("in.txt","r",stdin);
  43. // freopen("out.txt","w",stdout);
  44. int T;
  45. long long x,y;
  46. memset(dp,-,sizeof(dp));//这个初始化一定别忘记
  47. scanf("%d",&T);
  48. while(T--)
  49. {
  50. scanf("%I64d%I64d",&x,&y);
  51. printf("%I64d\n",calc(y)-calc(x-));
  52. }
  53. return ;
  54. }

64 / 95 Problem G HDU 3652 B-number

找出1~n范围内含有13并且能被13整除的数字的个数

  1. /*
  2. * HDU 3652 B-number
  3. * 含有数字13和能够被13整除的数的个数
  4. * dp[i][j][k][z]:i:处理的数位,j:该数对13取模以后的值,k:是否已经包含13,z结尾的数
  5. */
  6. #include <iostream>
  7. #include <string.h>
  8. #include <algorithm>
  9. #include <stdio.h>
  10. using namespace std;
  11. int dp[][][][];
  12. int bit[];
  13. int dfs(int pos,int num,bool t,int e,bool flag)
  14. {
  15. if(pos==-)return t&&(num==);
  16. if(!flag && dp[pos][num][t][e]!=-)
  17. return dp[pos][num][t][e];
  18. int end=flag?bit[pos]:;
  19. int ans=;
  20. for(int i=;i<=end;i++)
  21. ans+=dfs(pos-,(num*+i)%,t||(e==&&i==),i,flag&&(i==end));
  22. if(!flag)dp[pos][num][t][e]=ans;
  23. return ans;
  24. }
  25. int calc(int n)
  26. {
  27. int pos=;
  28. while(n)
  29. {
  30. bit[pos++]=n%;
  31. n/=;
  32. }
  33. return dfs(pos-,,,,);
  34. }
  35. int main()
  36. {
  37. //freopen("in.txt","r",stdin);
  38. //freopen("out.txt","w",stdout);
  39. int n;
  40. memset(dp,-,sizeof(dp));
  41. while(scanf("%d",&n)==)
  42. {
  43. printf("%d\n",calc(n));
  44. }
  45. return ;
  46. }

42 / 124 Problem H HDU 4734 F(x)

定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+...a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字。

题目给出a,b,求出0~b有多少个权值不大于f(a)的数。

dp[i][j]表示i位值<=j 的总数

  1. /* ***********************************************
  2. Author :kuangbin
  3. Created Time :2013/9/14 星期六 12:45:42
  4. File Name :2013成都网络赛\1007.cpp
  5. ************************************************ */
  6.  
  7. #pragma comment(linker, "/STACK:1024000000,1024000000")
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <iostream>
  11. #include <algorithm>
  12. #include <vector>
  13. #include <queue>
  14. #include <set>
  15. #include <map>
  16. #include <string>
  17. #include <math.h>
  18. #include <stdlib.h>
  19. #include <time.h>
  20. using namespace std;
  21.  
  22. int dp[][];
  23.  
  24. int bit[];
  25.  
  26. int dfs(int pos,int num,bool flag)
  27. {
  28. if(pos == -)return num >= ;
  29. if(num < )return ;
  30. if(!flag && dp[pos][num] != -)
  31. return dp[pos][num];
  32. int ans = ;
  33. int end = flag?bit[pos]:;
  34. for(int i = ;i <= end;i++)
  35. {
  36.  
  37. ans += dfs(pos-,num - i*(<<pos),flag && i==end);
  38. }
  39. if(!flag)dp[pos][num] = ans;
  40. return ans;
  41. }
  42.  
  43. int F(int x)
  44. {
  45. int ret = ;
  46. int len = ;
  47. while(x)
  48. {
  49. ret += (x%)*(<<len);
  50. len++;
  51. x /= ;
  52. }
  53. return ret;
  54. }
  55. int A,B;
  56. int calc()
  57. {
  58. int len = ;
  59. while(B)
  60. {
  61. bit[len++] = B%;
  62. B/=;
  63. //cout<<bit[len-1]<<endl;
  64. }
  65. //cout<<F(A)<<endl;
  66. return dfs(len-,F(A),);
  67. }
  68.  
  69. int main()
  70. {
  71. //freopen("in.txt","r",stdin);
  72. //freopen("out.txt","w",stdout);
  73. int T;
  74. int iCase = ;
  75. scanf("%d",&T);
  76. memset(dp,-,sizeof(dp));
  77. while(T--)
  78. {
  79. iCase++;
  80. scanf("%d%d",&A,&B);
  81. printf("Case #%d: %d\n",iCase,calc());
  82. }
  83. return ;
  84. }

11 / 20 Problem I ZOJ 3494 BCD Code
31 / 100 Problem J HDU 4507 吉哥系列故事――恨7不成妻

如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  1、整数中某一位是7;
  2、整数的每一位加起来的和是7的整数倍;
  3、这个整数是7的整数倍;

要求一个区间中和7无关的数的平方和。

需要用数位DP维护3个值:

1.与7无关的数的个数

2.与7无关的数的和

3、与7无关的数的平方和。

第一个是与7无关的数的个数,就是简单的数位DP了,很常规。

第二个与7无关的数的和的维护需要用到第一个个数。

处理到第pos个数位时,加上i*10^pos * 后面的个数

第三个的维护需要用到前面两个

(pre*10^pos + next)^2= (pre*10^pos)^2+2*pre*10^pos*next +next^2

  1. /*
  2. *  如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
  3.   1、整数中某一位是7;
  4.   2、整数的每一位加起来的和是7的整数倍;
  5.   3、这个整数是7的整数倍;
  6.  
  7. 求一个区间中与7无关的数的平方和
  8. */
  9. #include <iostream>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <algorithm>
  13. using namespace std;
  14. const long long MOD=1000000007LL;
  15. struct Node
  16. {
  17. long long cnt;//与7无关的数的个数
  18. long long sum;//与7无关的数的和
  19. long long sqsum;//平方和
  20. }dp[][][];//分别是处理的数位、数字和%7,数%7
  21. int bit[];
  22. long long p[];//p[i]=10^i
  23.  
  24. Node dfs(int pos,int pre1,int pre2,bool flag)
  25. {
  26. if(pos==-)
  27. {
  28. Node tmp;
  29. tmp.cnt=(pre1!= && pre2!=);
  30. tmp.sum=tmp.sqsum=;
  31. return tmp;
  32. }
  33. if(!flag && dp[pos][pre1][pre2].cnt!=-)
  34. return dp[pos][pre1][pre2];
  35. int end=flag?bit[pos]:;
  36. Node ans;
  37. Node tmp;
  38. ans.cnt=ans.sqsum=ans.sum=;
  39. for(int i=;i<=end;i++)
  40. {
  41. if(i==)continue;
  42. tmp=dfs(pos-,(pre1+i)%,(pre2*+i)%,flag&&i==end);
  43. ans.cnt+=tmp.cnt;
  44. ans.cnt%=MOD;
  45. ans.sum+=(tmp.sum+ ((p[pos]*i)%MOD)*tmp.cnt%MOD )%MOD;
  46. ans.sum%=MOD;
  47.  
  48. ans.sqsum+=(tmp.sqsum + ( (*p[pos]*i)%MOD )*tmp.sum)%MOD;
  49. ans.sqsum%=MOD;
  50. ans.sqsum+=( (tmp.cnt*p[pos])%MOD*p[pos]%MOD*i*i%MOD );
  51. ans.sqsum%=MOD;
  52. }
  53. if(!flag)dp[pos][pre1][pre2]=ans;
  54. return ans;
  55. }
  56. long long calc(long long n)
  57. {
  58. int pos=;
  59. while(n)
  60. {
  61. bit[pos++]=n%;
  62. n/=;
  63. }
  64. return dfs(pos-,,,).sqsum;
  65. }
  66. int main()
  67. {
  68. //freopen("in.txt","r",stdin);
  69. //freopen("out.txt","w",stdout);
  70. int T;
  71. long long l,r;
  72. p[]=;
  73. for(int i=;i<;i++)
  74. p[i]=(p[i-]*)%MOD;
  75. for(int i=;i<;i++)
  76. for(int j=;j<;j++)
  77. for(int k=;k<;k++)
  78. dp[i][j][k].cnt=-;
  79. scanf("%d",&T);
  80. while(T--)
  81. {
  82. scanf("%I64d%I64d",&l,&r);
  83. long long ans=calc(r);
  84. ans-=calc(l-);
  85. ans=(ans%MOD+MOD)%MOD;
  86. printf("%I64d\n",ans);
  87. }
  88. return ;
  89. }

42 / 75 Problem K SPOJ BALNUM Balanced Numbers

这题要求出现的数字,偶数出现奇数次,奇数出现偶数次。

用三进制表示0~9的状态

  1. //============================================================================
  2. // Name : SPOJ.cpp
  3. // Author :
  4. // Version :
  5. // Copyright : Your copyright notice
  6. // Description : Hello World in C++, Ansi-style
  7. //============================================================================
  8.  
  9. #include <iostream>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <algorithm>
  13. using namespace std;
  14. long long dp[][];
  15. //3进制表示数字0~9的出现情况,0表示没有出现,1表示奇数次,2表示偶数次
  16. int bit[];
  17. bool check(int s)
  18. {
  19. int num[];
  20. for(int i=;i<;i++)
  21. {
  22. num[i]=s%;
  23. s/=;
  24. }
  25. for(int i=;i<;i++)
  26. if(num[i]!=)
  27. {
  28. if(i%== && num[i]==)return false;
  29. if(i%== && num[i]==)return false;
  30. }
  31. return true;
  32. }
  33. int getnews(int x,int s)
  34. {
  35. int num[];
  36. for(int i=;i<;i++)
  37. {
  38. num[i]=s%;
  39. s/=;
  40. }
  41. if(num[x]==)num[x]=;
  42. else num[x]=-num[x];
  43. int news=;
  44. for(int i=;i>=;i--)
  45. {
  46. news*=;
  47. news+=num[i];
  48. }
  49. return news;
  50. }
  51. long long dfs(int pos,int s,bool flag,bool z)
  52. {
  53. if(pos==-)return check(s);
  54. if(!flag && dp[pos][s]!=-)
  55. return dp[pos][s];
  56. long long ans=;
  57. int end=flag?bit[pos]:;
  58. for(int i=;i<=end;i++)
  59. ans+=dfs(pos-,(z&&i==)?:getnews(i,s),flag&&i==end,z&&i==);
  60. if(!flag)dp[pos][s]=ans;
  61. return ans;
  62. }
  63. long long calc(long long n)
  64. {
  65. int len=;
  66. while(n)
  67. {
  68. bit[len++]=n%;
  69. n/=;
  70. }
  71. return dfs(len-,,,);
  72. }
  73. int main()
  74. {
  75. //freopen("in.txt","r",stdin);
  76. //freopen("out.txt","w",stdout);
  77. int T;
  78. memset(dp,-,sizeof(dp));
  79. long long a,b;
  80. scanf("%d",&T);
  81. while(T--)
  82. {
  83. cin>>a>>b;
  84. cout<<calc(b)-calc(a-)<<endl;
  85. }
  86. return ;
  87. }

ps:从这个题发现了pow的精度问题,呵呵

http://blog.csdn.net/u014665013/article/details/70990408

[kuangbin带你飞]专题十五 数位DP的更多相关文章

  1. 「kuangbin带你飞」专题十五 数位DP

    传送门 A.CodeForces - 55D Beautiful numbers 题意 一个正整数是 漂亮数 ,当且仅当它能够被自身的各非零数字整除.我们不必与之争辩,只需计算给定范围中有多少个漂亮数 ...

  2. 【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus

    A - Max Sum Plus Plus https://vjudge.net/contest/68966#problem/A http://www.cnblogs.com/kuangbin/arc ...

  3. [kuangbin带你飞]专题十 匹配问题

        A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找     ID Origin Title   61 / 72 Problem A HD ...

  4. [kuangbin带你飞]专题十 匹配问题 一般图匹配

    过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍 ...

  5. [kuangbin带你飞]专题十 匹配问题 二分匹配部分

    刚回到家 开了二分匹配专题 手握xyl模板 奋力写写写 终于写完了一群模板题 A hdu1045 对这个图进行 行列的重写 给每个位置赋予新的行列 使不能相互打到的位置 拥有不同的行与列 然后左行右列 ...

  6. [kuangbin带你飞]专题十 匹配问题 二分图多重匹配

    二分图的多重匹配问题不同于普通的最大匹配中的"每个点只能有最多一条边" 而是"每个点连接的边数不超过自己的限定数量" 最大匹配所解决的问题一般是"每个 ...

  7. [kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher 题解报告

    来刷kuangbin字符串了,字符串处理在ACM中是很重要的,一般比赛都会都1——2道有关字符串处理的题目,而且不会很难的那种,大多数时候都是用到一些KMP的性质或者找规律. 点击标题可跳转至VJ比赛 ...

  8. [kuangbin带你飞]专题十四 数论基础

            ID Origin Title   111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe   21 / 74 Problem B ...

  9. [kuangbin带你飞]专题十二 基础DP1

            ID Origin Title   167 / 465 Problem A HDU 1024 Max Sum Plus Plus   234 / 372 Problem B HDU 1 ...

随机推荐

  1. ExtJs学习笔记之FormPanel组件

    FormPanel组件 FormPanel 为 form 表单提供了一个标准的容器. 本质上还是一个标准的 Ext.panel.Panel, 只是自动创建了一个 BasicForm 来管理所有添加到 ...

  2. Android监听点击事件实现的三种方法

    监听点击事件实现的三种方法:1.匿名内部类2.外部类3.直接实现接口 1.匿名内部类: package com.jereh.calculator; import android.content.Con ...

  3. SVN-钩子祥解

    钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作 所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化属性的 ...

  4. 【jmeter】测试报告优化<一>

    具体问题如下: 1.Date report这里的时间没有正确显示出来 2.Summary里的字段Min Time和Max Time显示的是NaN,没有显示正确的时间. 本文主要解决上述两个问题,具体报 ...

  5. 【linux】linux如何进入单人维护模式修改root密码

  6. Visual对象之DrawingContext.DrawRectangle在有的状态下似乎并不能提高性能

    很多书上都提到使用Visual对象绘制图形可以提高绘图效率,但是经过本人亲测,结果却发现DrawingContext.DrawRectangle的效率远低于使用UIElement.Children.A ...

  7. c# string 数组转 list

    string str = "1,11,121,131"; var arr = str.Split(','); List<string> list = new List& ...

  8. 剑指offer系列33-----把二叉树打印成多行

    [题目]从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 方法一:直接打印 package com.exe7.offer; import java.util.LinkedList; i ...

  9. (转)如何在eclipse的配置文件里指定jdk路径

    本文转载自:http://songguoliang.iteye.com/blog/1752519 运行eclipse时报如下错误: 在eclipse的配置文件里指定jdk路径,只需在eclipse的配 ...

  10. 【PDF】java使用Itext生成pdf文档--详解

    [API接口]  一.Itext简介 API地址:javadoc/index.html:如 D:/MyJAR/原JAR包/PDF/itext-5.5.3/itextpdf-5.5.3-javadoc/ ...