[bzoj3733]Iloczyn 题解(搜索剪枝)

3733: [Pa2013]Iloczyn

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 741  Solved: 217
[Submit][Status][Discuss]

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
 
 

一开始还以为是什么神仙数论题,后来发现搜就完事了。

先预处理一下约数并排好序,设x表示可选x到cnt的所有因数,num表示已经选了num个,prod表示当前选取因数的乘积,然后一顿狂暴血怒滚键盘剪枝就水过了。

比较有效的一个是如果当前最小的num个可选因数的乘积都大于n就直接return false。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int T,n,K;
int fact[50005],cnt;
void div(int val)
{
    for(int i=1;i*i<=n;i++)
        if(n%i==0)
        {
            fact[++cnt]=i;
            if(i*i!=n)fact[++cnt]=n/i;
        }
    sort(fact+1,fact+cnt+1);
}
bool dfs(int x,int num,int prod)
{
    if(num==K&&prod==n)return 1;
    if(num>=K)return 0;
    if(x==cnt+1)return 0;
    if(cnt-x+1<K-num)return 0;
    int now=prod;
        for(int i=x,j=num+1;i<=cnt&&j<=K;i++,j++)
    {
        if(1LL*now*fact[i]>n)return 0;
        else now=1LL*now*fact[i];
    }
    if(dfs(x+1,num,prod))return 1;
    if(1LL*prod*fact[x]<=n&&dfs(x+1,num+1,prod*fact[x]))return 1;
    return 0;
}

void work()
{
    scanf("%d%d",&n,&K);
    cnt=0;
    div(n);
    if(cnt<K){puts("NIE");return ;}
    if(dfs(1,0,1))puts("TAK");
    else puts("NIE");
    return ;
}
int main()
{
    scanf("%d",&T);
    while(T--)work();
    return 0;
}
原文地址:https://www.cnblogs.com/Rorschach-XR/p/11378990.html