BZOJ3679: 数字之积

我们会发现对于一个乘积一定可以分解为2 3 5 7的倍数

然后就根据这个来做了预处理出每个数的幂次

总感觉数位DP用记忆化搜索更方便?

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
char c;
inline void read(ll &a)
{
    a=0;do c=getchar();while(c<'0'||c>'9');
    while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}

ll Pow3[1001];
ll Pow2[1001];
ll Pow5[1001];
ll Pow7[1001];
ll n;
const
  ll Mod=102367;
struct Rec
{
    ll x,cnt2,cnt3,cnt5,cnt7,res;
    inline ll Hash(){return ((x+cnt2*177+cnt3*2333+cnt5*6787+cnt7*323+res*641)%Mod+Mod)%Mod;}
    inline friend bool operator !=(Rec a,Rec b)
    {
    return (a.x^b.x)|(a.res^b.res)|(a.cnt2^b.cnt2)|(a.cnt3^b.cnt3)|(a.cnt5^b.cnt5)|(a.cnt7^b.cnt7);
    }
};
struct Hash
{
    Rec Key;
    ll Ans;
    Hash*next;
}*Table[Mod];
ll Ans;
inline bool Find(Rec Key,Hash *Cur)
{
    if(Cur==NULL)return false;
    if(Key!=Cur->Key)return Find(Key,Cur->next);
    Ans=Cur->Ans;
    return true;
}
inline void Insert(int Pl,Rec Key,ll Ans)
{
    Hash *tp=new Hash;
    tp->next=Table[Pl];
    tp->Ans=Ans;
    tp->Key=Key;
    Table[Pl]=tp;
}
int f,k;

ll F(ll x,ll cnt2,ll cnt3,ll cnt5,ll cnt7,ll res,bool R)
{
   Rec tp;
   ll t;
   if(Pow2[cnt2]*Pow3[cnt3]*Pow5[cnt5]*Pow7[cnt7]>n)return 0;

   if(x==0)
     return 1;
   tp.cnt2=cnt2,tp.cnt3=cnt3,tp.cnt5=cnt5,tp.cnt7=cnt7,tp.res=res,tp.x=x;
   if(R)tp.res=-1;
   if(Find(tp,Table[t=tp.Hash()]))return Ans;
   ll Ans=0;
   if(res>=x*1)
   {
      Ans+=F(x/10,cnt2,cnt3,cnt5,cnt7,res-x,R||(res>=2*x));
   }
   if(res>=x*2)
   {
      Ans+=F(x/10,cnt2+1,cnt3,cnt5,cnt7,res-2*x,R||(res>=3*x));
   }    
   if(res>=x*3)
   {
      Ans+=F(x/10,cnt2,cnt3+1,cnt5,cnt7,res-3*x,R||(res>=4*x));
   }   
   if(res>=x*4)
   {
      Ans+=F(x/10,cnt2+2,cnt3,cnt5,cnt7,res-4*x,R||(res>=5*x));
   }   
   if(res>=x*5)
   {
      Ans+=F(x/10,cnt2,cnt3,cnt5+1,cnt7,res-5*x,R||(res>=6*x));
   }   
   if(res>=x*6)
   {
      Ans+=F(x/10,cnt2+1,cnt3+1,cnt5,cnt7,res-6*x,R||(res>=7*x));
   }   
   if(res>=x*7)
   {
      Ans+=F(x/10,cnt2,cnt3,cnt5,cnt7+1,res-7*x,R||(res>=8*x));
   }   
   if(res>=x*8)
   {
      Ans+=F(x/10,cnt2+3,cnt3,cnt5,cnt7,res-8*x,R||(res>=9*x));
   }   
   if(res>=x*9)
   {
      Ans+=F(x/10,cnt2,cnt3+2,cnt5,cnt7,res-9*x,R||(res>=10*x));
   }   

   Insert(t,tp,Ans); 
   return Ans;
}

////__attribute__((optimize("O2"))
int main()
{
    ll L,R;
    Pow3[0]=Pow2[0]=Pow5[0]=Pow7[0]=1;
    for(ll i=1;i<=60;i++)
    Pow2[i]=Pow2[i-1]*2,
    Pow3[i]=Pow3[i-1]*3,
    Pow5[i]=Pow5[i-1]*5,
    Pow7[i]=Pow7[i-1]*7;
    read(n);
    read(L),read(R);
    L--,R--;
    ll b1=1,b2=1;
    while(b2<=R)b2=(b2<<3)+(b2<<1);
    while(b1<=L)b1=(b1<<3)+(b1<<1);

    b1/=10;b2/=10;
    ll ans1=L==0?0:F(b1,0,0,0,0,L,false);
    b1/=10;
    while(b1)
    {
      ans1+=F(b1,0,0,0,0,b1*10-1,false);
       b1/=10;
    }
    ll ans2=F(b2,0,0,0,0,R,false);
    b2/=10;
    while(b2)
    {
      ans2+=F(b2,0,0,0,0,b2*10-1,false);
       b2/=10;
    }
    printf("%lld\n",ans2-ans1);
//  printf("%d %d",f,k);
     return 0;

} 

你可能感兴趣的:(BZOJ3679: 数字之积)