题意:问你1到n中间有多少数包含13的子串,并且是13的倍数
思路:我们很容易想到,一个数是不是13的倍数,只需要进行同余模定理就可以了,然后在设置一个标志存储是否含有13的串,(我觉得这样做真的没有什么问题,但在记录答案的时候会多记录),然后我们说正确的状态怎么定义其实是多了一个位置,把刚才的标志改为3个状态,一个代表包含13,一个代表已1结尾,一个代表没有
代码:(聚聚们如果知道为什么两个状态会多记录答案,方便的话在下面留言,教教小弟)
#include <bits/stdc++.h> using namespace std; typedef long long LL; int a[55]; LL dp[55][20][5]; LL dfs(int pos,int m,int ok,bool limit) { // printf("test pos==%d pre==%d m==%d ok==%d limit==%d ",pos,pre,m,ok,limit); if(pos==-1){ return m==0&&ok==2; } if(!limit&&dp[pos][m][ok]!=-1) return dp[pos][m][ok]; int up=limit?a[pos]:9; LL ans=0; // printf("qqq pos==%d up==%d ",pos,up); for(int i=0;i<=up;i++){ int mx=(m*10+i)%13; int as=ok; if(ok==0&&i==1)as=1; if(ok==1&&i!=1)as=0; if(ok==1&&i==3)as=2; ans+=dfs(pos-1,mx,as,limit&&i==a[pos]); } // printf("zzz ans==%lld ",ans); if(!limit)dp[pos][m][ok]=ans; // printf("end pos==%d pre==%d m==%d ok==%d limit==%d ",pos,pre,m,ok,limit); return ans; } LL solve(int x) { int pos=0; while(x){ a[pos++]=x%10; x/=10; } return dfs(pos-1,0,0,true); } int main() { LL n; memset(dp,-1,sizeof(dp)); while(~scanf("%d",&n)){ printf("%lld ",solve(n)); } return 0; } /* 13 */