题解:[PA 2013] Iloczyn

题目传送门

题意分析

对于正整数 \(n,k\),求能否将 \(n\) 划分为 \(k\) 个不同的正整数的乘积,多测。

搜索

观察数据范围,可以发现 \(1\leq k\leq 20\),拆出来数的个数不会太多,因此考虑 DFS。

很容易写出一个暴力 DFS 的判断函数:

//last用于防止重复
bool check(int n,int k,int last=0){
	if(k==1){//边界:拆分为1个数
		return n>last;
	}
	for(int i=last+1;i<=n;i++){
		if(n%i==0){
			if(check(n/i,k-1,i)){
				return true;
			}
		}
	}
	return false;
}

但是这样显然是过不了的,实测只能获得 \(\text{54pts}\)

因此我们考虑剪枝

剪枝之一

check() 中枚举因数 \(i\) 可以优化,因为 \(i\) 如果取到 \(\sqrt[k]{n}\) 以上的时候是一定无解的。

那么优化后的判断函数为:

bool check(int n,int k,int last=0){
	if(k==1){ 
		return n>last; 
	}
	int Max=pow(n,1.0/k);
	for(int i=last+1;i<=Max;i++){
		if(n%i==0){
			if(check(n/i,k-1,i)){
				return true;
			}
		}
	}
	return false;
}

剪枝之二

显然,能够拆分为 \(k\) 个正整数的乘积的数必须大于 \(k!\)

而众所周知,阶乘的增长是非常迅速的,由计算器可得 \(13!=6227020800>10^9\)

因此当 \(k\geq13\) 的时候,直接输出 NIE 即可。

其他优化

意义不大,因为上面两个简单易懂的剪枝已经足以通过此题,但可以参考。

比如说预处理出 \(1\sim12\) 的阶乘,每次二分检验能否直接输出 NIE

或者说 \(\mathcal O(\sqrt n)\) 求出 \(n\) 的因数,然后在因数中枚举。

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
bool check(int n,int k,int last=0){
	if(k==1){ 
		return n>last; 
	}
	int Max=pow(n,1.0/k);
	for(int i=last+1;i<=Max;i++){
		if(n%i==0){
			if(check(n/i,k-1,i)){
				return true;
			}
		}
	}
	return false;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	int T;
	scanf("%d",&T);
	while(T--){
		int n,k;
		scanf("%d %d",&n,&k);
		printf("%s\n",(k<=12 && check(n,k)?"TAK":"NIE"));
	}
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2025-07-21 21:12  TH911  阅读(3)  评论(0)    收藏  举报