本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
【Codeforces】CodeTON Round 3 D - Count GCD | 数学、容斥
题目链接
题目
题目大意
对于给定的含有 个元素的数组 ,构造数组 ,使得对于 的所有的 均满足满足以下条件:
- 。
统计合法的 数组的数量,对 998244353 取余。
思路
因为
所以 ,先扫一遍是否存在 ,的情况,若存在则无解,否则统计在 中和 的最大公约数为 的个数。
又因为
所以我们只需要计算 里和 互质的数的个数。
怎样计算 里和 互质的数的个数呢?这是一个经典问题,我们可以使用容斥。
中 的倍数的数量非常容易计算,显然为 。
首先预处理出 的质因数,先从全体数中减去 的一个质因数的倍数的数量,但是 两个质因数的倍数会被减去两次,所以我们需要把 两个质因数的倍数的数量再加回来,同理需要把 三个质因数的倍数的数量减去……
上述过程可以用状压 dp 进行处理。因为 所以单组数据我们需要处理的 之积不超过 ,操作次数非常少,可以通过此题。
代码
#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
typedef pair<int,int> PII;
const int N=500001;
//const LL mod=1000000007;
const LL mod=998244353;
int n,tot;
LL m,k;
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}
LL a[N];
struct asdf{
int x,y;
}ans[N];
LL p[N];
LL getans(LL x,LL r)// 1 到 r 中与 x 互质的数的个数
{
if (x==1) return r;
tot=0;
LL y=x;
for (LL i=2;i*i<=x;++i)
if (x%i==0)
{
p[++tot]=i;
while (x%i==0) x/=i;
}
if (x>1) p[++tot]=x;
LL res=0;
for (int i=1;i<(1<<tot);++i)
{
LL cnt=-1;
LL mult=1;
for (int j=1;j<=tot;++j)
if (i&(1<<j-1))
{
cnt*=-1;
mult*=p[j];
}
mult=r/mult;
res+=mult*cnt;
}
if (res<0) return 0;
if (r-res<0) return 0;
return (r-res)%mod;
}
int solve()
{
scanf("%d",&n);
scanf("%lld",&m);
for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
for (int i=2;i<=n;++i)
if (a[i-1]%a[i]!=0) return printf("0\n"),0;
LL ans=1;
for (int i=2;i<=n;++i)
ans=ans*getans(a[i-1]/a[i],m/a[i])%mod;
printf("%lld\n",ans);
return 0;
}
int main()
{
int T=1;
for (scanf("%d",&T);T--;) solve();
return 0;
}