[BZOJ3733]Iloczyn
Description
给定正整数n和k,问能否将n分解为k个不同正整数的乘积
Input
第一行一个数T(T<=4000)表示测试组数
接下来T行每行两个数n(n<=10^9),k(k<=20)
Output
输出T行,若可以被分解,输出"TAK"否则输出"NIE"
Sample Input
3
15 2
24 4
24 5
15 2
24 4
24 5
Sample Output
TAK
TAK
NIE
TAK
NIE
好久不写搜索果然没什么剪枝的思路,其实这道题的剪枝也很好想
关键是效果非常显著
我们设$DFS(x,y,z)$表示到选到第$x$个因数还有$y$个没选乘积为$z$是否合法
然后我们预处理出来$f[i][j]$表示从$i$开始再选最小的$j$个的最小乘积
如果当前$z*f[x][y]>n$就一定没有合法方案了,加上这个剪枝后跑的飞快
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define M 2010 5 using namespace std; 6 int T,n,k,tot; 7 int q[M],f[M][22]; 8 bool dfs(int x,int y,int z) 9 { 10 if(!y) return n==z;--y; 11 while(x+y<=tot) 12 { 13 if(f[x][y]<0) return false; 14 if(1ll*f[x][y]*z>n) return false; 15 if(dfs(x+1,y,z*q[x])) return true; 16 x++; 17 } 18 return false; 19 } 20 int main() 21 { 22 scanf("%d",&T); 23 while(T--) 24 { 25 scanf("%d%d",&n,&k);tot=0; 26 for(int i=1; i*i<=n; i++) 27 if(n%i==0) 28 { 29 q[++tot]=i; 30 if(n/i!=i) q[++tot]=n/i; 31 } 32 sort(q+1,q+1+tot); 33 for(int i=1; i<=tot; i++) 34 { 35 long long t=1; 36 for(int j=0; j<k&&(i+j)<=tot; f[i][j++]=t) 37 if(t>0) {t*=q[i+j];if(t>n) t=-1;} 38 } 39 if(dfs(1,k,1)) puts("TAK"); 40 else puts("NIE"); 41 } 42 return 0; 43 }