您的位置:首页 > 其它

HDU 3652 数位DP

2014-06-06 22:15 387 查看
题目大意:给一个数字n,找出1-n中,有多少个数字,既能被13整除,又包含子串“13”。

很裸的数位DP了,

dp[ i ][ j ][ k ][ m ]:i位数,最高位是j类型(j==0,数字1;j==1,数字3;j==2,其他),k表示是否(1/0)包含“13”,余数为m的数字有多少。

cnt[ i ][ k ][ m ] = dp[ i ][ 0/1/2 ][ k ][ m ]

dfs()函数,dfs(int pos,int pre,int h13,int m,bool fg)

pos:需要填的最高位

pre:前面一位是否(1/0)为1

h13:前面是否(1/0)已经有“13”了

fg:前面每一位都达到了最大否

//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF=100011122;
const double INFF=1e100;
const double eps=1e-8;
const LL mod=9999991;
const int NN=10010;
const int MM=2000010;
/* ****************** */

int dp[15][3][2][13];
int cnt[15][2][13];
int p[15],m13[250];
int a[15];

void init(int n)
{
int i,j,k,m,x,nj,nk,nm,t;
memset(dp,0,sizeof(dp));
memset(cnt,0,sizeof(cnt));
dp[0][2][0][0]=1;
p[0]=1;
for(i=1;i<11;i++)
{
p[i]=p[i-1]*10%13;
}
for(i=0;i<200;i++)
{
m13[i]=i%13;
}

for(i=0;i<n;i++)
for(j=0;j<3;j++)
for(k=0;k<2;k++)
for(m=0;m<13;m++)
if(dp[i][j][k][m])
{
t=dp[i][j][k][m];
for(x=0;x<10;x++)
{
if(x==1)nj=0;
else if(x==3)nj=1;
else nj=2;
if( k==1 || (j==1&&x==1) )
nk=1;
else
nk=0;
nm=m13[ p[i]*x+m ];
dp[i+1][nj][nk][nm]+=t;
cnt[i+1][nk][nm]+=t;
}
}
}

int dfs(int pos,int pre,int h13,int m,bool fg)
{
if(pos==0)
{
return (h13==1 && m==0);
}
if(!fg)
{
int ans,needm=m13[ m*p[pos] ];
needm=m13[ 13-needm ];

ans=cnt[pos][1][needm];
if(h13==1)
{
ans+=cnt[pos][0][needm];
}
else if(pre==1)
{
ans+=dp[pos][1][0][needm];
}
return ans;
}
int i,ans=0;
for(i=0;i<=a[pos];i++)
{
if(h13 || (pre==1&&i==3))
ans+=dfs(pos-1,(i==1),1,m13[m*10+i],i==a[pos]);
else
ans+=dfs(pos-1,(i==1),0,m13[m*10+i],i==a[pos]);
}
return ans;
}

int calc(int x)
{
int tol=0;
do
{
a[++tol]=x%10;
x/=10;
}while(x);
return dfs(tol,0,0,0,1);
}

int main()
{
init(10);
int n,ans;
while(scanf("%d",&n)!=EOF)
{
ans=calc(n);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: