模拟赛 数位和乘积(时间限制 1000MS,内存限制 256MB)

【题目描述】

一个数字的数位和乘积为其各位数字的乘积。求所有的N位数中有多少个数的数位和乘积恰好为K。请注意,这里的N位数是可以有前导零的。比如01,02视为二位数,但是他们的数位和乘积都是0。

【输入格式】

一行两个整数N,K

【输出格式】

一个行一个整数表示结果。

【样例输入】

2 3

【样例输出】

2

【样例输入2】

2 0

【样例输出2】

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;
}

你可能感兴趣的:(动态规划,其他)