传送门

A.CodeForces - 55D Beautiful numbers

题意

一个正整数是 漂亮数 ,当且仅当它能够被自身的各非零数字整除。我们不必与之争辩,只需计算给定范围中有多少个漂亮数。

思路

因为问你的是一段区间内有多少数能整除他的所有非零数位

1-9,1,一定能被任何正整数整除,1-9的最小公倍数为2520

而1-2520中真正是1-9中的最小公倍数的只有48个

dp i j k:因为dp25,2520,[2520]开不下,所以我们要进行适当离散化

index[]数组标记1-2520,哪些是真正的最小公倍数,是第几个

所以dp[i][j][k]:长度为i的数,该数对2520取模为j,它的数位和的最小公倍数是第k个->index[i]

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const int mod=2520;
  17. const int maxn=1e6+50;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){if(b==0)return a;else return gcd(b,a%b);}
  20. int lcm(int a,int b){return (a*b)/gcd(a,b);}
  21. int islcm[mod+10];
  22. int num[200];
  23. ll dp[200][2550][50];
  24. void init(){
  25. int num=0;
  26. for(int i=1;i<=2520;i++){
  27. if(2520%i==0)islcm[i]=++num;
  28. }
  29. }
  30. ll dfs(int pos,int nownum,int nowlcm,bool limit){
  31. if(pos==-1)return nownum%nowlcm==0;
  32. if(!limit&&dp[pos][nownum][islcm[nowlcm]]!=-1)return dp[pos][nownum][islcm[nowlcm]];
  33. int up=limit?num[pos]:9;
  34. ll ans=0;
  35. for(int i=0;i<=up;i++){
  36. int nowsum=(nownum*10+i)%mod;
  37. int nowl=nowlcm;
  38. if(i)nowl=lcm(nowl,i);
  39. ans+=dfs(pos-1,nowsum,nowl,limit&&i==num[pos]);
  40. }
  41. if(!limit)dp[pos][nownum][islcm[nowlcm]]=ans;
  42. return ans;
  43. }
  44. ll ac(ll x){
  45. ll pos=0;
  46. while(x){
  47. num[pos++]=x%10;
  48. x/=10;
  49. }
  50. return dfs(pos-1,0,1,true);
  51. }
  52. int main()
  53. {
  54. std::ios::sync_with_stdio(false);
  55. std::cin.tie(0);
  56. std::cout.tie(0);
  57. memset(dp,-1,sizeof(dp));
  58. init();
  59. int t;
  60. cin>>t;
  61. while(t--){
  62. ll n,m;
  63. cin>>n>>m;
  64. cout<<ac(m)-ac(n-1)<<endl;
  65. }
  66. return 0;
  67. }

B.HDU - 4352 XHXJ's LIS

题意

问你一个longlong范围内(a,b)中每一位的数字组成的最长严格递增子序列(LIS)长度为K的个数

题意

首先 关系到数字和位数 数位DP

然后LIS 最长递增子序列利用二分查找当前递增子序列中是否有大于它的数,如果有替换最小的哪一个,如果没有就加入长度+1;可以利用状态压缩保存当前的最长递增子序列的类型;因为数字最多十个所以类型最多长度为10,用二进制的1表示当前位数的这个数在最长递增子序列中;

然后注意前导0的处理

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int lcm(int a,int b){return a*b/gcd(a,b);}
  21. int k;
  22. int num[21];
  23. ll dp[21][1<<11][11];
  24. int numcnt(int x){
  25. int cnt=0;
  26. for(int i=0;i<10;i++){
  27. if(x&(1<<i))cnt++;
  28. }
  29. return cnt;
  30. }
  31. int numchange(int x,int p){
  32. for(int i=p;i<=9;i++){
  33. if(x&(1<<i))return (x^(1<<i))|(1<<p);
  34. }
  35. return x|(1<<p);
  36. }
  37. ll dfs(int pos,int nownum,bool limit,bool zero){
  38. if(pos==-1)return numcnt(nownum)==k;
  39. if(!limit&&dp[pos][nownum][k]!=-1)return dp[pos][nownum][k];
  40. int up=limit?num[pos]:9;
  41. ll ans=0;
  42. for(int i=0;i<=up;i++){
  43. ans+=dfs(pos-1,(zero&&i==0)?0:numchange(nownum,i),limit&&i==num[pos],zero&&i==0);
  44. }
  45. if(!limit)dp[pos][nownum][k]=ans;
  46. return ans;
  47. }
  48. ll ac(ll x){
  49. ll pos=0;
  50. while(x){
  51. num[pos++]=x%10;
  52. x/=10;
  53. }
  54. return dfs(pos-1,0,true,true);
  55. }
  56. int main()
  57. {
  58. std::ios::sync_with_stdio(false);
  59. std::cin.tie(0);
  60. std::cout.tie(0);
  61. memset(dp,-1,sizeof(dp));
  62. int t;
  63. cin>>t;
  64. ll a,b;
  65. int cnt=0;
  66. while(t--){
  67. cin>>a>>b>>k;
  68. cout<<"Case #"<<++cnt<<": "<<ac(b)-ac(a-1)<<endl;
  69. }
  70. return 0;
  71. }

C.HDU - 2089 不要62

题意

中文题

思路

数位DP模板题

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6+50;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int num[20];
  21. int dp[20][2];
  22. int dfs(int pos,int pre,int sta,bool first){
  23. if(pos==-1)return 1;
  24. if(!first&&dp[pos][sta]!=-1)return dp[pos][sta];
  25. int up=first?num[pos]:9;
  26. int ans=0;
  27. for(int i=0;i<=up;i++){
  28. if(pre==6&&i==2)continue;
  29. if(i==4)continue;
  30. ans+=dfs(pos-1,i,i==6,first&&i==num[pos]);
  31. }
  32. if(!first)dp[pos][sta]=ans;
  33. return ans;
  34. }
  35. int ac(int x){
  36. int pos=0;
  37. while(x){
  38. num[pos++]=x%10;
  39. x/=10;
  40. }
  41. return dfs(pos-1,-1,0,true);
  42. }
  43. int main()
  44. {
  45. std::ios::sync_with_stdio(false);
  46. std::cin.tie(0);
  47. std::cout.tie(0);
  48. int n,m;
  49. memset(dp,-1,sizeof(dp));
  50. while(cin>>n>>m&&(n&&m)){
  51. cout<<ac(m)-ac(n-1)<<endl;
  52. }
  53. return 0;
  54. }

D.HDU - 3555 Bomb

题意

求1-n中出现49的数的个数,不要62的反例

思路1

不要62的反解 注意ac(n)算的是0-n之前的数其中包括了0 因为多减去了一个0所以结果要再加上0

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6+50;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int num[50];
  21. ll dp[50][2];
  22. ll dfs(int pos,int pre,int sta,bool first){
  23. if(pos==-1)return 1;
  24. if(!first&&dp[pos][sta]!=-1)return dp[pos][sta];
  25. int up=first?num[pos]:9;
  26. ll ans=0;
  27. for(int i=0;i<=up;i++){
  28. if(pre==4&&i==9)continue;
  29. ans+=dfs(pos-1,i,i==4,first&&i==num[pos]);
  30. }
  31. if(!first)dp[pos][sta]=ans;
  32. return ans;
  33. }
  34. ll ac(ll x){
  35. int pos=0;
  36. while(x){
  37. num[pos++]=x%10;
  38. x/=10;
  39. }
  40. return dfs(pos-1,-1,0,true);
  41. }
  42. int main()
  43. {
  44. std::ios::sync_with_stdio(false);
  45. std::cin.tie(0);
  46. std::cout.tie(0);
  47. ll n;
  48. memset(dp,-1,sizeof(dp));
  49. int t;
  50. cin>>t;
  51. while(t--){
  52. cin>>n;
  53. cout<<n-ac(n)+1<<endl;
  54. }
  55. return 0;
  56. }

思路2

正着做 DP[第几个数]//[这个数这个位是不是4]///[这个数前面存不存在49]

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6+50;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int num[200];
  21. ll dp[200][2][2];
  22. ll dfs(int pos,int pre,int sta,bool first,bool ok){
  23. if(pos==-1){
  24. if(ok)return 1;
  25. else
  26. return 0;
  27. }
  28. if(!first&&dp[pos][sta][ok]!=-1)return dp[pos][sta][ok];
  29. int up=first?num[pos]:9;
  30. ll ans=0;
  31. for(int i=0;i<=up;i++){
  32. ans+=dfs(pos-1,i,i==4,first&&i==num[pos],pre==4&&i==9||ok);
  33. }
  34. if(!first)dp[pos][sta][ok]=ans;
  35. return ans;
  36. }
  37. ll ac(ll x){
  38. ll pos=0;
  39. while(x){
  40. num[pos++]=x%10;
  41. x/=10;
  42. }
  43. return dfs(pos-1,-1,0,true,false);
  44. }
  45. int main()
  46. {
  47. std::ios::sync_with_stdio(false);
  48. std::cin.tie(0);
  49. std::cout.tie(0);
  50. memset(dp,-1,sizeof(dp));
  51. int t;
  52. cin>>t;
  53. while(t--){
  54. ll n;
  55. cin>>n;
  56. cout<<ac(n)<<endl;
  57. }
  58. return 0;
  59. }

E.POJ - 3252 Round Numbers

题意

求L到R中二进制里面0的数量大于等于1的数量的个数

思路

二进制的数位DP,但是注意这个有关前导0,如果有前导零的话遇到0就不能加上0的数量;

dp【第几位】【0的数量】【1的数量】

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int lcm(int a,int b){return a*b/gcd(a,b);}
  21. int num[200];
  22. ll dp[200][200][200];
  23. ll dfs(int pos,int num0,int num1,bool limit,bool zero){
  24. if(pos==-1)return num0>=num1;
  25. if(!limit&&dp[pos][num0][num1]!=-1)return dp[pos][num0][num1];
  26. int up=limit?num[pos]:1;
  27. ll ans=0;
  28. for(int i=0;i<=up;i++){
  29. if(i)ans+=dfs(pos-1,num0,num1+1,limit&&i==num[pos],zero&&i==0);
  30. else ans+=dfs(pos-1,num0+(zero?0:1),num1,limit&&i==num[pos],zero&&i==0);
  31. }
  32. if(!limit)dp[pos][num0][num1]=ans;
  33. return ans;
  34. }
  35. ll ac(ll x){
  36. ll pos=0;
  37. while(x){
  38. num[pos++]=x&1;
  39. x/=2;
  40. }
  41. return dfs(pos-1,0,0,true,true);
  42. }
  43. int main()
  44. {
  45. std::ios::sync_with_stdio(false);
  46. std::cin.tie(0);
  47. std::cout.tie(0);
  48. memset(dp,-1,sizeof(dp));
  49. ll n,m;
  50. cin>>n>>m;
  51. cout<<ac(m)-ac(n-1)<<endl;
  52. return 0;
  53. }

F.HDU - 3709 Balanced Number

题意

求范围内的平衡数字的个数,从数字到枢轴的距离是它与枢轴之间的偏移。然后可以计算左右部分的扭矩。如果它们是相同的,它是平衡的。平衡数字必须与其某些数字处的枢轴平衡。例如,4139是一个平衡数字,其中枢轴固定为3.对于左侧部分和右侧部分,扭矩分别为4 * 2 + 1 * 1 = 9和9 * 1 = 9。

思路

枚举枢轴的位置(1-len)然后和加起来,易知一个数最多只能有一个枢轴,假设有一个枢轴 后移动枢轴位置的,那么 平衡数字不可能会变成0.

然后再减去前导0的数比如00 000 0000

如果中间的平衡数的值小于0了那么这个数的这个位置为枢轴的肯定没有平衡数;比如前面已经4359以3为枢轴 左边是4*1 右边是5 ->4-5=-1 在过去值肯定比-1要小

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e6;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int lcm(int a,int b){return a*b/gcd(a,b);}
  21. int num[21];
  22. ll dp[21][21][2200];
  23. ll dfs(int pos,int on,int nownum,bool limit){
  24. if(pos==-1)return nownum==0;
  25. if(nownum<0)return 0;
  26. if(!limit&&dp[pos][on][nownum]!=-1)return dp[pos][on][nownum];
  27. int up=limit?num[pos]:9;
  28. ll ans=0;
  29. for(int i=0;i<=up;i++){
  30. ans+=dfs(pos-1,on,nownum+(pos+1-on)*i,limit&&i==num[pos]);
  31. }
  32. if(!limit)dp[pos][on][nownum]=ans;
  33. return ans;
  34. }
  35. ll ac(ll x){
  36. if(x<0)return 0;
  37. ll pos=0;
  38. while(x){
  39. num[pos++]=x%10;
  40. x/=10;
  41. }
  42. ll ans=0;
  43. for(int i=1;i<=pos;i++)ans+=dfs(pos-1,i,0,1);
  44. return ans-(pos-1);
  45. }
  46. int main()
  47. {
  48. std::ios::sync_with_stdio(false);
  49. std::cin.tie(0);
  50. std::cout.tie(0);
  51. memset(dp,-1,sizeof(dp));
  52. int t;
  53. cin>>t;
  54. ll a,b;
  55. int cnt=0;
  56. while(t--){
  57. cin>>a>>b;
  58. cout<<ac(b)-ac(a-1)<<endl;
  59. }
  60. return 0;
  61. }

G.HDU - 3652 B-number

题意

要13并且能被13整除的数;模板题,要标记当前余的数和前面的那个数!!和是否有13

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. #define pp pair<int,int>
  5. const ll mod=998244353;
  6. const int maxn=1e6+50;
  7. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  8. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  9. int lcm(int a,int b){return a*b/gcd(a,b);}
  10. int num[11];
  11. int dp[11][15][2][15];
  12. int dfs(int pos,int pre,bool flag,int nownum,bool limit){
  13. if(pos==-1)return (flag)&&(nownum==0);
  14. if(dp[pos][nownum][flag][pre]!=-1&&!limit)return dp[pos][nownum][flag][pre];
  15. int up=limit?num[pos]:9;
  16. int ans=0;
  17. for(int i=0;i<=up;i++){
  18. ans+=dfs(pos-1,i,flag||(pre==1&&i==3),(nownum*10+i)%13,limit&&(i==num[pos]));
  19. }
  20. if(!limit)dp[pos][nownum][flag][pre]=ans;
  21. return ans;
  22. }
  23. int ac(int x){
  24. int ans=0;
  25. while(x){
  26. num[ans++]=x%10;
  27. x/=10;
  28. }
  29. return dfs(ans-1,0,false,0,true);
  30. }
  31. int main()
  32. {
  33. std::ios::sync_with_stdio(false);
  34. std::cin.tie(0);
  35. std::cout.tie(0);
  36. int n;
  37. memset(dp,-1,sizeof(dp));
  38. while(cin>>n){
  39. cout<<ac(n)<<endl;
  40. }
  41. return 0;
  42. }

H.HDU - 4734 F(x)

题意

一个A 一个B,给出一个F(x)的定义,让你求出0-B中有多少个F(x)<=F(a)

思路

一开始是想直接存每个数的F(x)然后和F(a)比较,不过这样就不能记忆化搜索了,后来发现直接存F(a)-F(x)的差值就行了如果差值小于0就直接返回 ,而且F(a)的最大值只有20736左右

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. #define pp pair<int,int>
  5. const ll mod=998244353;
  6. const int maxn=1e6+50;
  7. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  8. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  9. int lcm(int a,int b){return a*b/gcd(a,b);}
  10. int num[11];
  11. int dp[11][20736];
  12. int dfs(int pos,bool limit,int sum){
  13. if(pos==-1)return sum>=0;
  14. if(sum<0)return 0;
  15. if(dp[pos][sum]!=-1&&!limit)return dp[pos][sum];
  16. int up=limit?num[pos]:9;
  17. int ans=0;
  18. for(int i=0;i<=up;i++){
  19. ans+=dfs(pos-1,limit&&(i==num[pos]),sum-i*(1<<pos));
  20. }
  21. if(!limit)dp[pos][sum]=ans;
  22. return ans;
  23. }
  24. int ac(int x,int sum){
  25. int ans=0;
  26. while(x){
  27. num[ans++]=x%10;
  28. x/=10;
  29. }
  30. return dfs(ans-1,true,sum);
  31. }
  32. int getA(int x){
  33. int ans=0;
  34. while(x){
  35. num[ans++]=x%10;
  36. x/=10;
  37. }
  38. int sum=0;
  39. for(int i=0;i<ans;i++){
  40. sum+=(1<<i)*num[i];
  41. }
  42. return sum;
  43. }
  44. int main()
  45. {
  46. std::ios::sync_with_stdio(false);
  47. std::cin.tie(0);
  48. std::cout.tie(0);
  49. memset(dp,-1,sizeof(dp));
  50. int t;
  51. cin>>t;
  52. int cnt=0;
  53. while(t--){
  54. int a,b;
  55. cin>>a>>b;
  56. int sum=getA(a);
  57. cout<<"Case #"<<++cnt<<": ";
  58. cout<<ac(b,sum)<<endl;
  59. }
  60. return 0;
  61. }

I.ZOJ - 3494 BCD Code

题意

给定N个01串,再给定区间[a,b],问区间[a,b]里面有多少个数转化成BCD码之后不包含任何前面给出01串。1 <= A <= B <= 10^200

题解

正好最近都在做AC自动机,一看到不包括前面的01串马上想到自动机....首先把前面的N个01串扔进AC自动机里面求出坏点,表示当前当前点可以走那些数字,然后判断0-9的BCD码有没有接触到不能走的点

注意数字太大要用字符串存取

这题真有趣,真好AC自动机和数位DP的结合

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=1e9+9;
  17. const int maxn=1500;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. struct Trie{
  21. int next[2010][2],fail[2010];bool end[2010];
  22. int L,root;
  23. int newnode(){
  24. for(int i=0;i<2;i++){
  25. next[L][i]=-1;
  26. }
  27. end[L++]=false;
  28. return L-1;
  29. }
  30. void init(){
  31. L=0;
  32. root=newnode();
  33. }
  34. void insert(char buf[]){
  35. int len=strlen(buf);
  36. int now=root;
  37. for(int i=0;i<len;i++){
  38. if(next[now][buf[i]-'0']==-1)
  39. next[now][buf[i]-'0']=newnode();
  40. now=next[now][buf[i]-'0'];
  41. }
  42. end[now]=true;
  43. }
  44. void build(){
  45. queue<int>Q;
  46. fail[root]=root;
  47. for(int i=0;i<2;i++)
  48. if(next[root][i]==-1)next[root][i]=root;
  49. else{
  50. fail[next[root][i]]=root;
  51. Q.push(next[root][i]);
  52. }
  53. while(!Q.empty()){
  54. int now=Q.front();
  55. Q.pop();
  56. if(end[fail[now]]==true)end[now]=true;
  57. for(int i=0;i<2;i++)
  58. if(next[now][i]==-1)next[now][i]=next[fail[now]][i];
  59. else{
  60. fail[next[now][i]]=next[fail[now]][i];
  61. Q.push(next[now][i]);
  62. }
  63. }
  64. }
  65. };
  66. Trie ac;
  67. int num[250];
  68. ll dp[250][2005];
  69. ll dfs(int pos,int sta,bool limit,bool zero){
  70. if(pos==-1)return !zero;
  71. if(!zero&&!limit&&dp[pos][sta]!=-1)return dp[pos][sta];
  72. int up=limit?num[pos]:9;
  73. ll ans=0;
  74. for(int i=0;i<=up;i++){
  75. if(zero&&i==0)ans=(ans+dfs(pos-1,sta,limit&&i==up,zero&&i==0)+mod)%mod;
  76. else{
  77. int nex=sta,x=i;
  78. bool flag=true;
  79. for(int j=(1<<3);j;j>>=1){
  80. int bit=x/j;x=x-bit*j;
  81. nex=ac.next[nex][bit];
  82. if(ac.end[nex]){
  83. flag=false;break;
  84. }
  85. }
  86. if(flag)ans=(ans+dfs(pos-1,nex,limit&&i==up,zero&&i==0)+mod)%mod;
  87. }
  88. }
  89. if(!zero&&!limit)dp[pos][sta]=ans;
  90. return ans;
  91. }
  92. ll acc(char x[]){
  93. int len=strlen(x);
  94. for(int i=0;i<len;i++)num[i]=x[len-1-i]-'0';
  95. return dfs(len-1,0,true,true);
  96. }
  97. char str[220];
  98. char st[220],ed[220];
  99. int main()
  100. {
  101. std::ios::sync_with_stdio(false);
  102. std::cin.tie(0);
  103. std::cout.tie(0);
  104. int t;
  105. cin>>t;
  106. while(t--){
  107. int n;
  108. cin>>n;
  109. ac.init();
  110. memset(dp,-1,sizeof(dp));
  111. for(int i=0;i<n;i++){
  112. cin>>str;
  113. ac.insert(str);
  114. }
  115. ac.build();
  116. cin>>st>>ed;
  117. int lena=strlen(st),p=lena-1;
  118. while(st[p]=='0')st[p--]='9';
  119. st[p]=st[p]-1;
  120. cout<<((acc(ed)-acc(st)+mod)%mod)<<endl;
  121. }
  122. return 0;
  123. }

J.HDU - 4507 吉哥系列故事――恨7不成妻

题意

求指定范围内与7不沾边的所有数的平方和。结果要mod 10^9+7

思路

与7不沾边的数需要满足三个条件。

①不出现7

②各位数和不是7的倍数

③这个数不是7的倍数

这三个条件都是基础的数位DP。

但是这题要统计的不是符合条件个数,而是平方和。

也就是说在DP时候,要重建每个数,算出平方,然后求和。

需要维护三个值(推荐使用结构体), 假定dfs推出返回的结构体是next,当前结果的结构体是ans

①符合条件数的个数 cnt

②符合条件数的和 sum

③符合添加数的平方和 sqsum

其中①是基础数位DP。②next.sum+(10len×i)×ans.cnt,其中(10len×i)×ans.cnt代表以len为首位的这部分数字和。

③首先重建一下这个数,(10len×i+x),其中x是这个数的后面部分,则平方和就是(10len×i)2+x2+2×10len×i×x,其中x2=next.sqsum

整体还要乘以next.cnt,毕竟不止一个。

这样sqsum+=next.sqsum

sqsum+=(2×10len×i×x)×next.cnt=(2×10len×i)×next.sum(神奇的化简)

sqsum+=(10len×i)2×next.cnt

mod之后统计函数也有个小陷阱,那就是f(r)在mod之后有可能小于f(l-1)。也就是要对负数取正数模。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. #define pp pair<int,int>
  5. const ll mod=1e9+7;
  6. const int maxn=1e6+50;
  7. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  8. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  9. int lcm(int a,int b){return a*b/gcd(a,b);}
  10. int num[20];
  11. ll ten[20];
  12. struct node{
  13. ll cnt,sqr,sum;
  14. bool vis;
  15. node(ll a=0,ll b=0,ll c=0,bool d=0):cnt(a),sqr(b),sum(c),vis(d){}
  16. }dp[20][11][11];
  17. node dfs(int pos,ll mod1,ll mod2,bool limit){
  18. if(pos==-1){
  19. if(mod1%7==0||mod2%7==0)return node(0);
  20. return node(1);
  21. }
  22. if(dp[pos][mod1][mod2].vis&&!limit)return dp[pos][mod1][mod2];
  23. int up=limit?num[pos]:9;
  24. node now;
  25. for(int i=0;i<=up;i++){
  26. if(i==7)continue;
  27. node tmp=dfs(pos-1,(mod1+i)%7,(mod2*10+i)%7,limit&&i==num[pos]);
  28. ll aa=i*ten[pos]%mod;
  29. now.cnt=(now.cnt+tmp.cnt)%mod;
  30. now.sum=(now.sum+aa*tmp.cnt%mod+tmp.sum)%mod;
  31. now.sqr=(aa*aa%mod*tmp.cnt%mod+2*aa*tmp.sum%mod+tmp.sqr+now.sqr)%mod;
  32. }
  33. if(!limit){
  34. dp[pos][mod1][mod2]=now;
  35. dp[pos][mod1][mod2].vis=1;
  36. }
  37. return now;
  38. }
  39. ll ac(ll x){
  40. int ans=0;
  41. while(x){
  42. num[ans++]=x%10;
  43. x/=10;
  44. }
  45. node ret=dfs(ans-1,0,0,1);
  46. return ret.sqr%mod;
  47. }
  48. int main()
  49. {
  50. std::ios::sync_with_stdio(false);
  51. std::cin.tie(0);
  52. std::cout.tie(0);
  53. int t;
  54. cin>>t;
  55. ten[0]=1;for(int i=1;i<=18;i++)ten[i]=ten[i-1]*10;
  56. while(t--){
  57. ll a,b;
  58. cin>>a>>b;
  59. cout<<(ac(b)-ac(a-1)+mod)%mod<<endl;
  60. }
  61. return 0;
  62. }

K.SPOJ - BALNUM Balanced Numbers

题意

问[L, R]内有多少数字,满足每个奇数都出现了偶数次,每个偶数都出现了奇数次(没有出现的数不考虑)

题解1

用三进制来表示状态,0表示没出现,1表示出现奇数次,2表示出现偶数次。

然后就是裸的数位DP了

特别注意&&的优先度是低于==的

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1e5+50;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int num[25];
  21. int three[10];
  22. ll dp[25][maxn];
  23. int isok(int sta){
  24. for(int i=0;i<=9;i++,sta/=3){
  25. int k=sta%3;
  26. if(!k)continue;
  27. if((i&1)&&(k&1))return 0;
  28. if(((i&1)==0)&&(k==2))return 0;
  29. }
  30. return 1;
  31. }
  32. int change(int sta,int i){
  33. int nu[10];
  34. for(int j=0;j<=9;j++,sta/=3)nu[j]=sta%3;
  35. if(nu[i]==0)nu[i]=1;
  36. else nu[i]=3-nu[i];
  37. for(int j=9;j>=0;j--)sta=sta*3+nu[j];
  38. return sta;
  39. }
  40. ll dfs(int pos,int sta,bool first,bool zero){
  41. if(pos==-1)return isok(sta);
  42. if(!first&&dp[pos][sta]!=-1)return dp[pos][sta];
  43. int up=first?num[pos]:9;
  44. ll ans=0;
  45. for(int i=0;i<=up;i++){
  46. if(zero&&i==0)
  47. ans+=dfs(pos-1,sta,first&&i==num[pos],zero&&i==0);
  48. else
  49. ans+=dfs(pos-1,change(sta,i),first&&i==num[pos],zero&&i==0);
  50. }
  51. if(!first)dp[pos][sta]=ans;
  52. return ans;
  53. }
  54. ll ac(ll x){
  55. int pos=0;
  56. while(x){
  57. num[pos++]=x%10;
  58. x/=10;
  59. }
  60. return dfs(pos-1,0,true,true);
  61. }
  62. int main()
  63. {
  64. std::ios::sync_with_stdio(false);
  65. std::cin.tie(0);
  66. std::cout.tie(0);
  67. memset(dp,-1,sizeof(dp));
  68. int t;
  69. cin>>t;
  70. while(t--){
  71. ll m,n;
  72. cin>>n>>m;
  73. cout<<ac(m)-ac(n-1)<<endl;
  74. }
  75. return 0;
  76. }

解法2

可以多出一阶存1-9是否出现过 不过数组不能开到1<<11 要开到1<<10+50左右不然会超时

  1. #include<algorithm>
  2. #include <iostream>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <time.h>
  8. #include <vector>
  9. #include <bitset>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long ll;
  15. #define pp pair<int,int>
  16. const ll mod=998244353;
  17. const int maxn=1024+5;
  18. const ll inf=0x3f3f3f3f3f3f3f3fLL;
  19. int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
  20. int num[25];
  21. ll dp[25][maxn][maxn];
  22. int isok(int sta,int haha){
  23. for(int i=0;i<=9;i++){
  24. if((haha&(1<<i))==0)continue;
  25. if(i&1){//奇数出现偶数次
  26. if(sta&(1<<i)){
  27. return 0;
  28. }
  29. }
  30. else{
  31. if((sta&(1<<i))==0){
  32. return 0;
  33. }
  34. }
  35. }
  36. return 1;
  37. }
  38. int change(int sta,int i){
  39. return sta^(1<<i);
  40. }
  41. ll dfs(int pos,int sta,int haha,bool first,bool zero){
  42. if(pos==-1)return isok(sta,haha);
  43. if(!first&&dp[pos][sta][haha]!=-1)return dp[pos][sta][haha];
  44. int up=first?num[pos]:9;
  45. ll ans=0;
  46. for(int i=0;i<=up;i++){
  47. ll now=change(sta,i);
  48. if(zero&&i==0)
  49. ans+=dfs(pos-1,sta,haha,first&&i==num[pos],zero&&i==0);
  50. else
  51. ans+=dfs(pos-1,change(sta,i),haha|(1<<i),first&&i==num[pos],zero&&i==0);
  52. }
  53. if(!first)dp[pos][sta][haha]=ans;
  54. return ans;
  55. }
  56. ll ac(ll x){
  57. int pos=0;
  58. while(x){
  59. num[pos++]=x%10;
  60. x/=10;
  61. }
  62. return dfs(pos-1,0,0,true,true);
  63. }
  64. int main()
  65. {
  66. std::ios::sync_with_stdio(false);
  67. std::cin.tie(0);
  68. std::cout.tie(0);
  69. memset(dp,-1,sizeof(dp));
  70. int t;
  71. cin>>t;
  72. while(t--){
  73. ll m,n;
  74. cin>>n>>m;
  75. cout<<ac(m)-ac(n-1)<<endl;
  76. }
  77. return 0;
  78. }

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

  1. 「kuangbin带你飞」专题十二 基础DP

    layout: post title: 「kuangbin带你飞」专题十二 基础DP author: "luowentaoaa" catalog: true tags: mathj ...

  2. 「kuangbin带你飞」专题十四 数论基础

    layout: post title: 「kuangbin带你飞」专题十四 数论基础 author: "luowentaoaa" catalog: true tags: mathj ...

  3. 「kuangbin带你飞」专题十九 矩阵

    layout: post title: 「kuangbin带你飞」专题十九 矩阵 author: "luowentaoaa" catalog: true tags: mathjax ...

  4. 「kuangbin带你飞」专题十八 后缀数组

    layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kua ...

  5. 「kuangbin带你飞」专题二十 斜率DP

    layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...

  6. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  7. 「kuangbin带你飞」专题十七 AC自动机

    layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...

  8. [kuangbin带你飞]专题十五 数位DP

            ID Origin Title   62 / 175 Problem A CodeForces 55D Beautiful numbers   30 / 84 Problem B HD ...

  9. kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

    第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一 ...

随机推荐

  1. 玩转Openstack之Nova中的协同并发(一)

    玩转Openstack之Nova中的协同并发(一) 前不久参加了个Opnstack的Meetup,其中有一个来自EasyStack的大大就Nova中的协同并发做了一番讲解,有所感触,本想当天就总结一下 ...

  2. 利用binlog server及Xtrabackup备份集来恢复误删表(drop)

      Preface       Today I'm gonna test how to rescue a dropped table from binlog server based on a ful ...

  3. 基于Python的selenuim自动化测试尝试

    工作这么多年了,终于狠下心好好开始学学自动化测试相关知识,揭开这层神秘的面纱. 困难重重,障碍很多,但好在每天都多少有点小收获. 很感谢一个QQ好友推荐的虫师,也非常感谢在这个契机读到了虫师编著的&l ...

  4. Lua1

    使用lua进行脚本编程有很多优点: 1 代码体积小 2 执行速度快 3 安全性较高等 4 但是最大的优点是修改后的代码不需要重新编译即可生效,而高级语言的代码经过修改后需要经过重新编译或者解释后才能生 ...

  5. c语言版贪吃蛇小游戏

    编译环境:windows 7 64位 编译工具:codeblocks 13.12 备注:未使用graphics.h 声明:个人原创,未经允许,禁止转载!!! 数据结构:双向链表 1.程序未使用grap ...

  6. 初识 HTML5(一)

    H5其实就是H4的一个增强版本,我们在利用H5进行网页的构造会更简便,标签语义更简洁明了.首先,我们要理解HTML4,它是HTML的标记+css2+JavaScript的一些基本应用,简言之,就是AP ...

  7. 再看数据库——(5)Group By与Order By

    在使用sql语句时,很多人都会分不清order by与group by,其实简单的说: order by -- 排序 group by --分组 1.order by是行的排序,默认为升序. 有两种方 ...

  8. hexo站点地图

    将网站链接提交到百度 百度搜索引擎提交入口 有三种验证方式,我选择Html标签验证,在themes\next\layout\_partials\head.swing中添加验证代码: <meta ...

  9. PHP与web 页面交互

    PHP与Web页面交互是实现PHP网站与用户交互的重要手段.在PHP中提供了两种与Web页面交互的方法,一种是通过Web表单提交数据,另一种是通过URL参数传递. 这里我们将详细讲解表单的相关知识,为 ...

  10. 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法

    题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...