题意:
找出区间[li,ri]有多少个符合要求的数:
1、这个数里面有13
2、这个数可以被13整除
题解:
这个题目和之前的有点不一样就是这个题目要我们求包含13的(之前做过的都是不包含)。但是都差不多了,顶多就是状态开大一点就可以了
1、如果它前面已经有13了,那么状态就是2
2、如果前面没有13,且它的上一位是1,那么它的状态就是1
3、如果前面没有13,且它的上一位不是1,那么状态就是0
至于状态之间的转换就看代码吧!
然后就是还要被13取余,取余运算符是很浪费时间的,那么我们可以采用秦九韶取余
(a+b)%mod=((a%mod)+(b%mod))%mod
(a*b)%mod=((a%mod)*(b%mod))%mod
那么12%mod=((1%mod)*10+2)%mod
dp方程:
dp[x][y][z]表示:在枚举第x位,它的状态为y(这个状态就是包含13那个),递归取余的结果是z
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 const int maxn=25; 7 typedef long long ll; 8 ll v[maxn],dp[maxn][3][15],ci; 9 ll dfs(ll pos,bool limit,ll is,ll mod) 10 { 11 if(pos==-1) 12 { 13 if(is==2 && mod==0) 14 { 15 return 1; 16 } 17 return 0; 18 } 19 ll tmp=0; 20 if(!limit && dp[pos][is][mod]!=-1) return dp[pos][is][mod]; 21 ll up=limit?v[pos]:9; 22 for(ll i=0; i<=up; ++i) 23 { 24 //取余时候秦九韶算法 25 ll nmod = (mod*10+i)%13; 26 ll nstatus = is; // 有点else s = statu 的意思 27 //没想到它的状态有三个,我只考虑到了高位有13和没有13.但是还要考虑他的上一位是不是1 28 //这一点一定要考虑,大家可以想一想 29 if(is==0 && i==1)//高位不含13,并且末尾不是1,现在末尾添1返回1状态 30 nstatus = 1; 31 else if(is==1 && i!=1 && i!=3)//高位不含13,且末尾是1,现在末尾添加的不是1返回0状态 32 nstatus = 0; 33 else if(is==1 && i==3)//高位不含13,且末尾是1,现在末尾添加3返回2状态 34 nstatus = 2; 35 tmp+=dfs(pos-1,limit && i==v[pos],nstatus,nmod); 36 } 37 if(!limit) dp[pos][is][mod]=tmp; 38 //只有上界为9的时候才会往dp数组里面存,因为这样能节省更多的时间 39 return tmp; 40 } 41 ll solve(ll sum) 42 { 43 ll pos=0; 44 while(sum) 45 { 46 v[pos++]=sum%10; 47 sum/=10; 48 } 49 ci=pos; 50 return dfs(pos-1,1,0,0); 51 } 52 int main() 53 { 54 ll n; 55 memset(dp,-1,sizeof(dp)); 56 while(~scanf("%I64d",&n)) 57 { 58 59 printf("%I64d ",solve(n)); 60 } 61 return 0; 62 }