poj-3899-The Lucky Numbers 模拟+数学

题目链接:

http://poj.org/problem?id=3899

题目意思:

求给定区间内,只含4、7的数的个数以及通过反转后在该区间内的个数和。

解题思路:

模拟+数学。

代码解释的很详细,请看代码。

 

#include<iostream>

#include<cmath>

#include<cstdio>

#include<cstdlib>

#include<string>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<set>

#include<stack>

#include<list>

#include<queue>

#define eps 1e-6

#define INF 0x1f1f1f1f

#define PI acos(-1.0)

#define ll __int64

#define lson l,m,(rt<<1)

#define rson m+1,r,(rt<<1)|1

using namespace std;



/*

freopen("data.in","r",stdin);

freopen("data.out","w",stdout);

*/

char A[50],B[50];

//g1(a,b,len) 表示1-a中后缀为b的lucky数,其中len是b的长度

//g2(a,b)表示1-a中反转后大于b的lucky数

//A-B 之间的lucky数个数为 g1(B,0,0)-g1(A-1,0,0)

//反转后在A-B 之间的lucky数为 g2(A,A)-g2(A,B)+g2(B,B)-g2(A,B)



ll g1(char * a,char * b,int len)

{

   int alen=strlen(a);

   ll res=0;

   bool ism=false;



   for(int i=0;i<len;i++) //比较a的后len位与b的大小,>=

   {

      int j=i+alen-len;

      if(a[j]>b[i])

         break;

      else if(a[j]<b[i])

      {

         ism=true;

         break;

      }

   }

   if(len==0)  //先算出低于alen位的总的lucky数

   {

      for(int i=1;i<alen;i++)

         res+=(ll)1<<i;  //i位的话一共有2^i个lucky数

   }//如果len!=0 那么前面的m位中也有1-m,这种情况好像没考虑啊

   int m=alen-len; //计算与a位数相同lucky数

   int i;

   for(i=0;i<m;i++) //一位一位从前往后考虑

   {

      if(a[i]>'7') //4和7都可以

      {

         res+=(ll)1<<(m-i);

         break;

      }

      else if(a[i]=='7') //4一定可以,7再往后计算

         res+=(ll)1<<(m-i-1);//把是4的情况计算清楚,后面就是7的情况

      else if(a[i]>'4'&&a[i]<'7')

      {

         res+=(ll)1<<(m-i-1); //放4的情况,后面可以任意

         break;

      }

      else if(a[i]<'4')

         break;

   }

   if((i==m)&&!ism) //计算临界情况

      res++;

   return res;

}



ll g2(char * a,char * b) //1-a之间,反转后大于b的lucky数

{  //b的长度肯定要>=a的长度

    int alen=strlen(a);

    char tmp[50],*last=&tmp[49];  //从后往前

    ll res=0;



    for(int i=0;i<alen;i++)

    {

       if(b[i]>'7')  //高位已经超过7了,不可能超过它了

         break ;

       else if(b[i]=='7') //边界情况

            *(last--)='7';

       else if(b[i]>'4'&&b[i]<'7') //只要满足这

       {

          *last='7'; //只要把后面的这一位置成7,前面的可以任意了

          res+=g1(a,last,i+1);

          break;

       }

       else if(b[i]=='4')

       {

          *last='7';

          res+=g1(a,last,i+1); //把这位放7,前面的就任意了

          *(last--)='4'; //然后把它放4作为临界情况

       }

       else

       {

          *last='7'; //后面放7,前面就任意了

          res+=g1(a,last,i+1);

          *last='4'; //后面放4,前面就任意了

          res+=g1(a,last,i+1);

          break;

       }

    }

    //因为是算大于的情况,临界情况就不用考虑了

    return res;

}



int main()

{

   int  t;



   char aa[4]="999",bb[2]="7";

   printf("%I64d\n",g1(aa,bb,1));



   scanf("%d",&t);

   while(t--)

   {

      scanf("%s%s",A,B);

      int lea=strlen(A),leb=strlen(B);



      if(A[lea-1]!='0')

         --A[lea-1]; //是零的话就无所谓了

      ll ans=0;

      ans+=(g1(B,NULL,0)-g1(A,NULL,0)+g2(A,A)+g2(B,B));

      if(lea==leb)

         ans-=(2*g2(A,B));

      printf("%I64d\n",ans);



   }

   return 0;

}










 

 

你可能感兴趣的:(number)