HDOJ3652解题报告【数位DP】
题目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=3652
题目概述:
给出一个数n,求出1~n中所有包含“13”并且是13的倍数的数的个数。例如13满足条件,而143虽然是13的倍数,不过不包含“13”,所以不满足条件。
大致思路:
这种类型的题应该很容易看出是数位DP,这里设f[i,j,k,l]表示i位数当前位是j,这个数mod13=k的情况,l=1表示包含“13”,l=0表示不包含。
转移的话详见代码。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <vector> #include <ctime> #include <map> #include <stack> #include <queue> #include <cstring> #include <algorithm> using namespace std; #define sacnf scanf #define scnaf scanf #define scanfi(x) scanf("%d",&x) #define scanfd(x) scanf("%lf",&x) #define scanfl(x) scanf("%lld",&x) #define scanfc(x) scanf("%c",&x) #define scanfs(x) scanf("%s",&x) #define maxn 110 #define maxm 10 #define inf 1061109567 #define Eps 0.00001 const double PI=acos(-1.0); #define mod 1000000007 #define MAXNUM 10000 void Swap(int &a,int &b) {int t=a;a=b;b=t;} int Abs(int x) {return (x<0)?-x:x;} typedef long long ll; typedef unsigned int uint; int f[11][10][13][2]; //f[i,j,k,l] i位数当前为是j,mod13=k的情况,l=1表示包含13 int num[11]; int power(int a,int b) { int ans=1; while(b) { if(b&1) ans*=a; a*=a;b>>=1; } return ans; } int calc(int x) { int cnt=0,ans=0,temp=0; while(x) { num[cnt++]=x%10; x/=10; } num[cnt]=0;bool flag=false; for(int i=cnt-1;i>=0;i--) { for(int j=0;j<num[i];j++) { ans+=f[i+1][j][(13-temp%13)%13][1]; if(flag) ans+=f[i+1][j][(13-temp%13)%13][0]; else if(j==3&&num[i+1]==1) ans+=f[i+1][j][(13-temp%13)%13][0]; } if(num[i+1]==1&&num[i]==3) flag=true; temp+=num[i]*power(10,i); } return ans; } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); //clock_t st=clock(); int n; for(int i=0;i<10;i++) f[1][i][i][0]=1; for(int i=2;i<=10;i++) { for(int j=0;j<10;j++) { for(int k=0;k<10;k++) { for(int l=0;l<13;l++) { f[i][j][(l+j*power(10,i-1))%13][1]+=f[i-1][k][l][1]; if(j==1&&k==3) { f[i][j][(l+j*power(10,i-1))%13][1]+=f[i-1][k][l][0]; } else f[i][j][(l+j*power(10,i-1))%13][0]+=f[i-1][k][l][0]; } } } } while(~scanf("%d",&n)) { int ans=calc(n+1); printf("%d\n",ans); } //clock_t ed=clock(); //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC); return 0; }