hdu3555数论dp(第一个数位dp)

来源:互联网 发布:nginx 网站根目录 编辑:程序博客网 时间:2024/06/06 19:37

具体解释就不写了,详细的可以参考http://www.cnblogs.com/liuxueyang/archive/2013/04/14/3020032.html,写得不错,蛮详细的

在大区间内查询含有49的数字的个数

Source Code

#include<stdio.h>#include<string>#include<string.h>#include<algorithm>#include<map>#include<set>#include<queue>#include<vector>#include<iostream>#include<stack>#include<cmath>using namespace std;int t;unsigned long long n;long long dp[30][3];int digit[30]; /*dp[i][0]表示的长度为i不含49的个数 dp[i][1]表示的是长度为i不含49,但是以9为开头的结点 dp[i][2] 表示的是长度为i含49的数字的个数 因此我们可以得到每个dp的方程式dp[i][0]=dp[i-1][0]*10-dp[i-1][1];dp[i][1]=dp[i-1][0];dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; */ void init(){  memset(dp,0,sizeof(dp));  dp[0][0]=1;  for(int i=1;i<20;i++)//枚举长度  {     dp[i][0]=dp[i-1][0]*10-dp[i-1][1];     dp[i][1]=dp[i-1][0];     dp[i][2]=dp[i-1][2]*10+dp[i-1][1];  }   //cout<<dp[19][0]<<endl;} void solve(unsigned long long  n)//苦逼,在这里忘记转了,WA了好多次 {   memset(digit,0,sizeof(digit));   n++;//这里是要求的是1——n的范围,加上1是保证假如后面是49的,要算上去    long long ans=0;   int len=0;   int last=0;   while(n)   {     digit[++len]=n%10;     n/=10;   }   //从高位到低位进行枚举   int flag=0;   for(int i=len;i>=1;i--)   {         ans+=dp[i-1][2]*digit[i];//加上后面含有49的个数显然是对的          if(flag)//表示的是之前已经含有了49          {            ans+=dp[i-1][0]*digit[i]; //既然之前已经有49了,并且你前面已经讨论                                      //过了后面存在49的情况了,那么现在讨论的                                      //是后面没有49的情况,之前我不懂得是假如这一位是4,后面的是9呢?                                      //后来才发现,题目只是要求出现49即可,因此                                      //不管该位如何取值,只要出现了就行了                                                   }         else//前面没有49          {            if(digit[i]>4)//就是当前位大于4,那么假如是4的话就可以知道的是加上后面开头是9的            {              ans+=dp[i-1][1];             }          }            if(digit[i]==9&&last==4)         {           flag=1;         }         last=digit[i];   }    cout<<ans<<endl;}int main(void){   scanf("%d",&t);   init();   while(t--)   {     cin>>n;     solve(n);   }   return 0;}


0 0
原创粉丝点击