T14 Make It One (CF1043F)
T14 Make It One (CF1043F)
CF传送门
洛谷传送门
题意简述
题解
思路
一眼看上去很简单的样子,却又想不到什么妙方法
特性很多,不如先来研究一下答案的特征?
答案最长只有7,因为只要不是无解,每加入一个数必定至少从gcd中去除一个质因数
最极限的情况:(转自ZEZ题解)
a[1]= 3*5*7*11*13*17 a[2]=2 * 5*7*11*13*17 a[3]=2*3 * 7*11*13*17 a[4]=2*3*5 * 11*13*17 a[5]=2*3*5*7 * 13*17 a[6]=2*3*5*7*11 * 17 a[7]=2*3*5*7*11*13
于是我们枚举答案为
接下来怎么办呢?
一个很巧妙的想法:DP!
虽然只是要求我们判断是否有满足条件的解
但我们可以来计数(虽然看似多此一举,但方便转移)
设
最大公因数为
只需从能被i整除的数中选出
这其中还包含最大公因数不为
于是——
其中
显然是从大往小dp
当然我们总不能从无穷大开始吧,要从
只要
注意事项
- 做着做着你就会发现组合数太大了……
所以要模一个大质数
比如
逆元直接打表噢
-
无需预处理
-
记得清空
AC代码
#include<bits/stdc++.h>
using namespace std;
const long long N=300005,mod=998244353;
long long n,maxer=-1e9;
long long a[N],cnt[N],dp[N];
long long fx[8]={0,1,499122177,332748118,249561089,598946612,166374059,142606336};
long long C(long long m,long long n){
if(m<n) return 0;
long long ans=1;
for(long long i=m;i>=m-n+1;i--) ans=ans*i%mod;
ans=ans*fx[n]%mod;
return ans;
}
int main(){
scanf("%lld",&n);
for(long long i=1;i<=n;i++){
scanf("%lld",&a[i]);
maxer=max(maxer,a[i]);
for(long long j=1;j<=sqrt(a[i]);j++)//预处理cnt
if(a[i]%j==0){
cnt[j]++;
if(a[i]!=j*j) cnt[a[i]/j]++;
}
}
for(long long len=1;len<=7;len++){//枚举答案
for(long long i=maxer;i>=1;i--){
dp[i]=C(cnt[i],len);
for(long long j=2;i*j<=maxer;j++)
dp[i]=(dp[i]-dp[i*j])%mod;//枚举转移
}
if(dp[1]) {printf("%lld",len);return 0;}//如果有解就输出
}
printf("-1");
}