题目大意:求1到n中有多少个数含“49”
第一次接触按位DP,参考了别人的题解。
第一个代码运行速度快些(31ms),但状态的转移的分析比较麻烦,第二个代码要慢些(125ms),但code比较方便。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #define LEN 22 typedef __int64 LL; char s[LEN]; LL dp[LEN][3][2]; int next(int cur,int in) { if(cur==2 || cur==1&&in==9) return 2; return in==4; } LL DP(char s[],int len) { memset(dp,0,sizeof(dp)); dp[0][0][1]=1; for(int i=1;i<=len;i++) { dp[i][0][0]=9*dp[i-1][0][0]+8*dp[i-1][1][0]; dp[i][1][0]=dp[i-1][0][0]+dp[i-1][1][0]; dp[i][2][0]=10*dp[i-1][2][0]+dp[i-1][1][0]; for(int j=0;j<s[i]-'0';j++) { dp[i][next(0,j)][0]+=dp[i-1][0][1]; dp[i][next(1,j)][0]+=dp[i-1][1][1]; dp[i][next(2,j)][0]+=dp[i-1][2][1]; } dp[i][next(0,s[i]-'0')][1]+=dp[i-1][0][1]; dp[i][next(1,s[i]-'0')][1]+=dp[i-1][1][1]; dp[i][next(2,s[i]-'0')][1]+=dp[i-1][2][1]; } return dp[len][2][0]+dp[len][2][1]; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%s",s+1); printf("%I64d\n",DP(s,strlen(s+1))); } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #define LEN 22 typedef __int64 LL; char s[LEN]; LL dp[LEN][3][2]; int nextstate(int cur,int in) { if(cur==2 || cur==1&&in==9) return 2; return in==4; } int nextflag(int cur,int in,int max) { if(cur==1 && in==max) return 1; if(cur==1 && in>max) return -1; return 0; } LL DP(char s[],int len) { memset(dp,0,sizeof(dp)); dp[0][0][1]=1; for(int i=1;i<=len;i++) { for(int state=0;state<3;state++) { for(int flag=0;flag<2;flag++) { for(int j=0;j<10;j++) { if(nextflag(flag,j,s[i]-'0')==-1) continue; dp[i][nextstate(state,j)][nextflag(flag,j,s[i]-'0')]+=dp[i-1][state][flag]; } } } } return dp[len][2][0]+dp[len][2][1]; } int main() { freopen("in.txt","r",stdin); int t; scanf("%d",&t); while(t--) { scanf("%s",s+1); printf("%I64d\n",DP(s,strlen(s+1))); } return 0; }