1. 程式人生 > >BZOJ3733]Iloczyn

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 }