一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。
一行两个整数N,K
一个行一个整数表示结果。
2 3
2
2 0
19
对于20%:N <= 6。
对于50%:N<=16
存在另外30%:K=0。
对于100%:N <= 50,0 <= K <= 10^9。
唉,我太弱了……根本不会做题。
首先20分爆搜,据说有30分可拿,要加一些小的优化。
#include
#include
#include
#include
#include
#include
#include
#define inf 1<<30
#define ll long long
using namespace std;
int n;
ll m,ct;
void dfs(int w,ll s)
{
if(w>n)
{if(s==m) ct++;
return;
}
ll i,num=s;
for(i=0;i<=9;i++)
{if(m!=0&&i==0) continue;
if(m%i!=0||num*i>m) continue;
num*=i;
dfs(w+1,num);
num/=i;
}
}
int main()
{
freopen("digit.in","r",stdin);
freopen("digit.out","w",stdout);
scanf("%d%I64d",&n,&m);
if(m!=0) dfs(1,1);
printf("%I64d\n",ct);
return 0;
}
然后,50分的dp是因式分解。
1、当k=0时,因为一个数位可以填0~9共10个数,所以有10^n的方案,然后对于所有位,数字都不为0的方案数共有9^n。故当k=0时,答案为10^n-9^n。
2、当k!=0时,因为一个数位可以填1~9共9个数,且这10个数可分为2,3,5,7这四个质数的乘积。所以先因式分解,若有>7的质数则方案数为0;否则考虑5维数组dp:f[i][j][k][g][h]表示用到第i位,数的乘积为2^j*3^k*5^g*7^h时的方案数。
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int n,t1,t2,t3,t4;
ll K,f[20][32][32][32][32];
void doit()
{
ll a=1,b=1;
int i;
for(i=1;i<=n;i++) {a=a*10; b=b*9;}
printf("%I64d\n",a-b);
}
void work()
{
ll Kk=K;
while(Kk%2==0) {Kk/=2; t1++;}
while(Kk%3==0) {Kk/=3; t2++;}
while(Kk%5==0) {Kk/=5; t3++;}
while(Kk%7==0) {Kk/=7; t4++;}
if(Kk>1) {printf("0\n"); return;}
int i,j,k,h,g;
f[0][0][0][0][0]=1;
for(i=1;i<=n;i++)
for(j=0;j<=t1;j++)
for(k=0;k<=t2;k++)
for(h=0;h<=t3;h++)
for(g=0;g<=t4;g++)
{f[i][j][k][h][g]+=f[i-1][j][k][h][g];
if(j-1>=0) f[i][j][k][h][g]+=f[i-1][j-1][k][h][g];
if(k-1>=0) f[i][j][k][h][g]+=f[i-1][j][k-1][h][g];
if(j-2>=0) f[i][j][k][h][g]+=f[i-1][j-2][k][h][g];
if(h-1>=0) f[i][j][k][h][g]+=f[i-1][j][k][h-1][g];
if(j-1>=0&&k-1>=0) f[i][j][k][h][g]+=f[i-1][j-1][k-1][h][g];
if(g-1>=0) f[i][j][k][h][g]+=f[i-1][j][k][h][g-1];
if(j-3>=0) f[i][j][k][h][g]+=f[i-1][j-3][k][h][g];
if(k-2>=0) f[i][j][k][h][g]+=f[i-1][j][k-2][h][g];
}
printf("%I64d\n",f[n][t1][t2][t3][t4]);
}
int main()
{
freopen("digit.in","r",stdin);
freopen("digit.out","w",stdout);
scanf("%d%I64d",&n,&K);
if(K==0) doit();
else work();
return 0;
}
最后,我们感觉时间没有可以优化的了,其实剩下的50分就是高精度了,高精度加法、减法、高精乘单精你懂得。
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int n,K,t1,t2,t3,t4;
int f[32][20][13][10][102];
void mul(int *a,int b)
{
int i;
for(i=1;i<=100;i++) a[i]*=b;
for(i=1;i<=100;i++) {a[i+1]+=a[i]/10; a[i]%=10;}
}
void jian(int *a,int *b,int *c)
{
int i;
for(i=100;i>0;i--) c[i]=a[i]-b[i];
for(i=1;i<=100;i++)
{if(c[i]<0)
{c[i+1]--; c[i]+=10;}
}
}
void jia(int *a,int *b)
{
int i;
for(i=1;i<=100;i++) a[i]+=b[i];
for(i=1;i<=100;i++)
{a[i+1]+=a[i]/10; a[i]%=10;}
}
void doit()
{
int w,a[102],b[102],c[102];
memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c));
a[1]=b[1]=1;
int i;
for(i=1;i<=n;i++) {mul(a,10); mul(b,9);}
jian(a,b,c);
w=100;
while(c[w]==0) w--;
for(i=w;i>0;i--) printf("%d",c[i]);
printf("\n");
}
void work()
{
int Kk=K;
while(Kk%2==0) {Kk/=2; t1++;}
while(Kk%3==0) {Kk/=3; t2++;}
while(Kk%5==0) {Kk/=5; t3++;}
while(Kk%7==0) {Kk/=7; t4++;}
if(Kk>1) {printf("0\n"); return;}
int i,j,k,g,h,w;
f[0][0][0][0][1]=1;
for(i=1;i<=n;i++)
for(j=t1;j>=0;j--)
for(k=t2;k>=0;k--)
for(h=t3;h>=0;h--)
for(g=t4;g>=0;g--)
{if(j-1>=0) jia(f[j][k][h][g],f[j-1][k][h][g]);
if(k-1>=0) jia(f[j][k][h][g],f[j][k-1][h][g]);
if(j-2>=0) jia(f[j][k][h][g],f[j-2][k][h][g]);
if(h-1>=0) jia(f[j][k][h][g],f[j][k][h-1][g]);
if(j-1>=0&&k-1>=0) jia(f[j][k][h][g],f[j-1][k-1][h][g]);
if(g-1>=0) jia(f[j][k][h][g],f[j][k][h][g-1]);
if(j-3>=0) jia(f[j][k][h][g],f[j-3][k][h][g]);
if(k-2>=0) jia(f[j][k][h][g],f[j][k-2][h][g]);
}
w=100;
while(!f[t1][t2][t3][t4][w]) w--;
for(i=w;i>0;i--)
printf("%d",f[t1][t2][t3][t4][i]);
printf("\n");
}
int main()
{
freopen("digit.in","r",stdin);
freopen("digit.out","w",stdout);
scanf("%d%d",&n,&K);
if(K==0) doit();
else work();
return 0;
}