[BZOJ3679][数位DP]数字之积

来源:互联网 发布:霍尼韦尔净水器 知乎 编辑:程序博客网 时间:2024/05/21 14:46

学一发数位DP
如果直接记录乘积的话有109的情况,但是因为每一位只有1~9,所以最后乘积只有2 3 5 7的质因数,那么把在第i为放0~9转化成放入多少个2 3 5 7
f(i,c2,c3,c5,c7,j)表示转移到从高到低的第i位,因数2的个数为c2,3的个数为c3,5的个数为c5,7的个数为c7,j表示到i位的数字是否等于R的,然后转移一下 就好了…

#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;int n;int w[20],wt;int add[10][5];ll f[2][32][21][14][13][2];ll p2[32],p3[21],p5[14],p7[13];ll L,R;inline ll solve(ll lt,int n){  memset(f,0,sizeof(f));  int k=0; wt=0; ll x=lt,ret=0;  while(x) w[++wt]=x%10,x/=10;  for(int i=1;i<=w[wt];i++)    if(i>n) break; else      if(i==w[wt]) f[0][add[i][1]][add[i][2]][add[i][3]][add[i][4]][1]=1;      else f[0][add[i][1]][add[i][2]][add[i][3]][add[i][4]][0]=1;  for(int j=wt-1;j;j--){    k^=1;    for(int i=1;i<=9;i++)      if(i<=n) f[k][add[i][1]][add[i][2]][add[i][3]][add[i][4]][0]=1;    for(int i1=0;i1<=30;i1++)      if(p2[i1]<=n)    for(int i2=0;i2<=19;i2++)      if(p3[i2]*p2[i1]<=n)        for(int i3=0;i3<=13;i3++)          if(p5[i3]*p3[i2]*p2[i1]<=n)        for(int i4=0;i4<=11;i4++)          if(p7[i4]*p2[i1]*p3[i2]*p5[i3]<=n){            ll now=p2[i1]*p3[i2]*p5[i3]*p7[i4];            for(int i=1;i<=9;i++){              if(i*now>n) break;              f[k][i1+add[i][1]][i2+add[i][2]][i3+add[i][3]][i4+add[i][4]][0]+=f[k^1][i1][i2][i3][i4][0];              if(i>w[j]) continue;              if(i<w[j]) f[k][i1+add[i][1]][i2+add[i][2]][i3+add[i][3]][i4+add[i][4]][0]+=f[k^1][i1][i2][i3][i4][1];              else f[k][i1+add[i][1]][i2+add[i][2]][i3+add[i][3]][i4+add[i][4]][1]+=f[k^1][i1][i2][i3][i4][1];            }          }    for(int i1=0;i1<=30;i1++)      for(int i2=0;i2<=19;i2++)    for(int i3=0;i3<=13;i3++)      for(int i4=0;i4<=11;i4++)        f[k^1][i1][i2][i3][i4][0]=f[k^1][i1][i2][i3][i4][1]=0;  }  for(int i1=0;i1<=30;i1++)    for(int i2=0;i2<=19;i2++)      for(int i3=0;i3<=13;i3++)    for(int i4=0;i4<=11;i4++)      ret+=f[k][i1][i2][i3][i4][0],f[k][i1][i2][i3][i4][0]=f[k][i1][i2][i3][i4][1]=0;  return ret;}int main(){  cin>>n>>L>>R;  p2[0]=p3[0]=p5[0]=p7[0]=1;  for(int i=1;i<=30;i++) p2[i]=p2[i-1]*2;  for(int i=1;i<=19;i++) p3[i]=p3[i-1]*3;  for(int i=1;i<=13;i++) p5[i]=p5[i-1]*5;  for(int i=1;i<=11;i++) p7[i]=p7[i-1]*7;  add[2][1]=1; add[3][2]=1; add[4][1]=2; add[5][3]=1;  add[6][1]=1; add[6][2]=1; add[7][4]=1; add[8][1]=3;  add[9][2]=2;  cout<<solve(R,n)-solve(L,n)<<endl;  return 0;}
0 0
原创粉丝点击