bzoj3733 [Pa2013]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
正解:搜索。
直接筛出所有约数,然后搜索就行了。
有一个剪枝,就是如果现在可以选的最小的$k-now$的数与当前乘积的乘积大于$n$,就可以直接剪掉了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 6 using namespace std; 7 8 int sum[100010][22],fac[100010],n,k,tot; 9 10 il int gi(){ 11 RG int x=0,q=1; RG char ch=getchar(); 12 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 13 if (ch=='-') q=-1,ch=getchar(); 14 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 15 return q*x; 16 } 17 18 il void factor(RG int n){ 19 tot=0; 20 for (RG int i=2;i*i<=n;++i){ 21 if (n%i) continue; fac[++tot]=i; 22 if (i*i!=n) fac[++tot]=n/i; 23 } 24 sort(fac+1,fac+tot+1); return; 25 } 26 27 il int dfs(RG int now,RG int rem,RG int pro){ 28 if (!rem) return n==pro; 29 for (RG int i=now;i+rem<=tot+1;++i){ 30 if (sum[i][rem]==-1) return 0; 31 if (1LL*pro*sum[i][rem]>n) return 0; 32 if (dfs(i+1,rem-1,pro*fac[i])) return 1; 33 } 34 return 0; 35 } 36 37 il void work(){ 38 n=gi(),k=gi(); if (k==1){ puts("TAK"); return; } 39 if (k==2){ puts(n!=1 ? "TAK" : "NIE"); return; } factor(n),--k; 40 for (RG int i=1;i<=tot;++i){ 41 sum[i][0]=1; 42 for (RG int j=1;j<=k;++j){ 43 if (sum[i][j-1]==-1 || 1LL*sum[i][j-1]*fac[i+j-1]>n) sum[i][j]=-1; 44 else sum[i][j]=sum[i][j-1]*fac[i+j-1]; 45 } 46 } 47 puts(dfs(1,k,1) ? "TAK" : "NIE"); return; 48 } 49 50 int main(){ 51 #ifndef ONLINE_JUDGE 52 freopen("Iloczyn.in","r",stdin); 53 freopen("Iloczyn.out","w",stdout); 54 #endif 55 RG int T=gi(); 56 while (T--) work(); 57 return 0; 58 }