1. 程式人生 > >【PA2013】【BZOJ3733】Iloczyn

【PA2013】【BZOJ3733】Iloczyn

layer tdi ide 因數 sort clu std addclass view

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
HINT

Source

如今BZOJ上不去沒有中文題面也沒法在BZOJ提交T_T
在Main上交了一發過了
爆搜+剪枝
分解因子.
dfs(now,x,pro)表示還可選x個因子,當前乘積為pro,選因子的範圍在全部因子裏now到m個然後是否可能湊出乘積為n
Claris的優雅版剪枝:從now位開始向後選x個較小的數,若乘積大於n能夠剪枝
瀟爺的更加厲害的做法:
TimeMachine的Blog(為什麽辣麽長)

18:34UPD.光榮倒數第一233

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define MAXN 10010
using namespace std;
int T,n,k,m;
int divisor[MAXN];
LL f[MAXN][30];//f[i][j]表示從i開始最小j個因數乘積  
bool dfs(int now,int x,int pro)
{
    if
(!x) return pro==n; x--; for (;now+x<=m;now++) { if (f[now][x]<0) return 0; if (f[now][x]*(LL)pro>n) return 0; if (dfs(now+1,x,pro*divisor[now])) return 1; } return 0; } int main() { scanf("%d",&T); while (T--) { scanf("%d%d"
,&n,&k);m=0; for (int i=1;i*i<=n;i++) if (n%i==0) { divisor[++m]=i; if (i*i!=n) divisor[++m]=n/i; } sort(divisor+1,divisor+m+1);LL pro; for (int i=1;i<=m;i++) { pro=1; for (int j=0;j<k&&i+j<=m;f[i][j++]=pro) if (pro>0) { pro*=divisor[i+j]; if (pro>n) pro=-1; } } puts(dfs(1,k,1)?"TAK":"NIE"); } }

【PA2013】【BZOJ3733】Iloczyn