【hdu3652】数位dp(浅尝ACM-A)
向大佬学习
第一次写博客有点紧张,也算是小萌新的突破吧
这次主要是总结一下校内的ACM比赛的各种题,主要是新思路以及学到的新知识
先放一张
下面开始说正事
题面
A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string “13” and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.Input
Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).Output
Print each answer in a single line.Sample Input
13
100
200
1000Sample Output
1
1
2
2
乍眼一看,像极了数位dp,可是怎么判断是否能被13整除呢?之前学过做过的数位dp的限制条件都是有没有包含某数、不包含某数等。这告诉我们需要新思维了。
我们来回想一下普通的数位dp
ll dfs(int pos,,bool lead,bool limit)
{
if(pos==-1) return 1;
if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];
int up=limit?a[pos]:9;
ll ans=0;
for(int i=0;i<=up;i++)
{
if() ...
else if()...
ans+=dfs(pos-1,,lead && i==0,limit && i==a[pos])
}
if(!limit && !lead) dp[pos][state]=ans;
return ans;
}
其实就是记忆化搜索,其中dp[]表示第pos位的state状态,之所以可以直接调用返回,是因为不管前面的位怎么搞,只要符合第pos位的state状态,后面的情况就都定了,所以只需算一次,储存以后直接调用(limit==1要单独计算,以前就在这里挂了)
那么现在重点来了,state是一个很是重要的突破点,以前的思维就局限在“13”出现过没有,而处理能否被13整除,即为 i mod 13 == 0
所以dp数组就确定了: dp[i][j][k],i表示第i位,j=0,1,2,j=0表示还没有出现过“13”,j=1表示前一位是“1”,j=2表示已经出现了“13”,k表示当前的数mod13的值。
转移方程:
1、j=0,(1)该位为“1”,下传j=1;(2)不为“1”,下传j=0
2、j=1,(1)“3”,j=2:(2)“1”,j=1;(3)else,j=0;
3、j=2,直接下传j=2
4、k=(k*10)% 13(想想为什么)
然后就显而易见了
下面放代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[15];
int b[15],len;
int dp[15][3][13];
int dfs(int pos,bool limit,int appr,int mod,bool lead){//注意还要判断前导零的问题
if(pos==len+1){
if(appr==2&&mod==0&&lead==0) return 1;
else return 0;
}
if((!limit)&&dp[pos][appr][mod]!=-1) return dp[pos][appr][mod];
int up=limit?b[pos]:9;
int ans=0;
for(int i=0;i<=up;i++){
if(appr==0){
if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
}
if(appr==1){
if(i==3) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
else if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
}
if(appr==2) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
}
if(!limit) dp[pos][appr][mod]=ans;
return ans;
}
int main(){
while(scanf("%s",a+1)!=EOF){
len=strlen(a+1);
for(int i=1;i<=len;i++){
b[i]=a[i]-'0';
}
memset(dp,-1,sizeof(dp));
int ans=dfs(1,1,0,0,1);
printf("%d\n",ans);
}
return 0;
}
总结:
对数位dp有了更新的认识,各种不同的限制条件可以化为多个state,state是状态,不只是出现了什么数字而已