[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

Sample Output

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

 

posted @ 2018-11-25 11:42  Slr  阅读(228)  评论(0编辑  收藏  举报