题意
给定 1e9 以内的正整数 n,d,问 n 能否由至少两种不同的方式由漂亮数相乘得到;
漂亮数的定义为:能被 d 整除,但不能被 d * d 整除;
思路
n 有一系列数相乘得到,则每一个数都是 n 的因子,可以把 n 的因子枚举出,然后做完全背包,即可的得到 n 的方案数;
1e9 以内的数的因子数最多 1300 多个,完全可以枚举;在背包之前需要对因子离散化,但对 1e9 以内的数做离散化,我们开不下 1e9 的数组,如果用 map 的话,会多一个 log 的时间复杂度;从 dls 那学了一种方法:我们以 1e5 为界,开两个数组分别存 1e5 之前以及 1e5 之后的元素的离散化值,看代码比较容易懂;
//mx为1e5,id存1e5之前数的离散化值,gid存1e5之后数的离散化值
for(int i = 1 ;i <= cnt ;i++){
if(factor[i] <= mx) id[factor[i]] = i;
else gid[n / factor[i]] = i;
}
之后就是完全背包的操作了;
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int f[100010];
int factor[1400],cnt;
int id[100010],gid[100010];
int mx=100010;
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _;
cin>>_;
while(_--){
memset(f,0,sizeof(f));
cnt=0;
ll n,d;
cin>>n>>d;
for(int i=1;i*i<=n;i++){
if(n%i==0){
factor[++cnt]=i;
if(i*i!=n) factor[++cnt]=n/i;
}
}
sort(factor+1,factor+cnt+1);
for(int i=1;i<=cnt;i++){
if(factor[i]<=mx) id[factor[i]]=i;
else gid[n/factor[i]]=i;
}
f[1]=1;
for(int i=1;i<=cnt;i++){
if(factor[i]%d==0&&(factor[i]/d)%d!=0){
for(int j=1;j<=cnt;j++){
if((n/factor[i])%factor[j]) continue;
int x=factor[i]*factor[j];
int y;
if(x<=mx) y=id[x];
else y=gid[n/x];
f[y]=f[y]+f[j];
}
}
}
if(f[cnt]>=2) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}