13 100 200 1000
1 1 2 2
题意:给你一个数n,让你求1~n中有多少数x符合x%13==0 且x中出现过“13”这个子串。
思路:用dfs(pre,pos,num,flag,limit)来数出所有符合条件的数,其中pre表示这一位的上一位是什么,pos表示当前正循环到哪个位置,num表示到这一位时的总和(%13后,且这一位还没有算),flag表示之前的字符串中是否已经出现过"13"这个字符串,limit表示当前这位是有限制还是没有限制的,有限制的话,这一位最高遍历到wei[pos],没有限制的话最高遍历到9.另外没有剪枝的话会超时,所以用dp[pre][pos][num][flag]表示在limit==0的情况下,后面可以加上的值,如果(pre,pos,flag)这个状态已经遍历过的话,就不用遍历一遍了。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<bitset> #include<algorithm> using namespace std; typedef long long ll; typedef long double ldb; #define inf 99999999 #define pi acos(-1.0) #define maxn 805 int wei[15]; int dp[11][40][15][2];//到i位置%13为j且是否含有13的flag值为k的方案数 int dfs(int pre,int pos,int num,int flag,int limit){ int i,j; if(pos==0){ if((num%13==0) && (flag==1))return 1; return 0; } if((limit==0) && (dp[pre][pos][num][flag]!=-1) ){ return dp[pre][pos][num][flag]; } int sum=0; int num1,flag1; if(limit==0){ for(j=0;j<=9;j++){ num1=(num*10+j)%13; flag1=flag; if((pre==1) && (j==3) ){ flag1=1; } sum+=dfs(j,pos-1,num1,flag1,0); } } else if(limit==1){ for(j=0;j<=wei[pos];j++){ num1=(num*10+j)%13; flag1=flag; if((pre==1) && (j==3) ){ flag1=1; } if(j<wei[pos])sum+=dfs(j,pos-1,num1,flag1,0); else sum+=dfs(j,pos-1,num1,flag1,1); } } if(limit==0){ dp[pre][pos][num][flag]=sum; } return sum; } int solve(int x) { int i,j,len=0,t=x; while(t){ wei[++len]=t%10; t/=10; } wei[len+1]=0; memset(dp,-1,sizeof(dp)); int sum; sum=dfs(0,len,0,0,1); return sum; } int main() { int n,m,i,j; while(scanf("%d",&n)!=EOF) { printf("%d\n",solve(n)); } }