首页 > 代码库 > hdu3652(数位dp)
hdu3652(数位dp)
题意:求1-n(n<=1000000000)的数中,技能被13整除,又包含13子串的数的个数;
解法:数位dp。LL dp[pre][now][have][iflow][rem]记录着第pre位为now,have表示前边是否出现过13,iflow表示dp过程否有降低,rem表示后续需要的余数是多少。
代码:
/****************************************************** * author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 const double pi=acos(-1.0); typedef long long LL; const int Max=10100; const int INF=1000000007; LL dp[20][20][2][2][15]; int reminder[20]; int num[30]; LL dfs(int pre,int now,bool have,bool iflow,int rem) { if(pre==0) return have&&rem==0; if(dp[pre][now][have][iflow][rem]!=-1) return dp[pre][now][have][iflow][rem]; int en=iflow? 9 : num[pre-1]; LL ans=0; for(int i=0;i<=en;i++) { int tool=((rem-(i*reminder[pre-1])%13)+13)%13; if(now==1&&i==3) ans+=dfs(pre-1,i,1,iflow||i!=en,tool); else ans+=dfs(pre-1,i,have,iflow||i!=en,tool); } return dp[pre][now][have][iflow][rem]=ans; } void init() { reminder[0]=1; for(int i=1;i<=10;i++) reminder[i]=(reminder[i-1]*10)%13; } LL solve(LL n) { int p=0; memset(dp,-1,sizeof dp); while(n) { num[p++]=n%10; n/=10; } LL ans=0; for(int i=0;i<=num[p-1];i++) { int tool=(i*reminder[p-1])%13; ans+=dfs(p-1,i,0,i!=num[p-1],(13-tool)%13); } return ans; } int main() { int n; init(); while(cin>>n) { cout<<solve(n)<<‘\n‘; } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。