题目链接:Problem - 1750D - Codeforces
input:
5
3 5
4 2 1
2 1
1 1
5 50
2 3 5 2 3
4 1000000000
60 30 1 1
2 1000000000
1000000000 2
output:
3
1
0
595458194
200000000
题意:
给定一个长度为 n 的数组 a ,数组中所有元素的大小均不超过 m,试问有多少种方式构造长度为 n 的数组 b,满足任意 1 <= i <= n,有gcd(b1, b2, b3, ..., bi) == ai
思路:
首先判断无解情况。对于 2 <= i <= n,若 ai 不能被 ai-1 整除,则无解。
本体的题意十分清晰,对于某个 i ,若想满足题意条件,只需满足 gcd(ai-1, bi) == ai,其中 bi <= m,化简得 gcd(ai-1 / ai, bi / ai) == 1 , bi <= m / ai.
也就是说,找到所有 x,满足gcd(ai-1 / ai, x) == 1 且 x <= m / ai 即可。
对于一定范围内与某个数互质的数的数量,使用容斥定理即可解决问题,只需要求出范围内与该数不互质的数,不重不漏计数,最后与总量相减即可,具体见代码。
将每个 bi 的方案数求出来,所有答案相乘取模,即可得出答案。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define endl "\n"
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int mod=998244353;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
int t,n,m;
ll a[N];
vector<ll> vec;
void prime(ll s)
{
vec.clear();
for(ll i=2;i*i<=s;i++)
{
if(s%i==0)
{
vec.pb(i);
while(s%i==0)
s/=i;
}
}
if(s>1)
vec.pb(s);
return;
}
ll k;
ll ss;
void dfs(int cnt,ll sum,int pick)
{
if(cnt==vec.size())
{
if(pick>=1)
{
if(pick&1)
{
ss+=k/sum;
}
else
{
ss-=k/sum;
}
}
return;
}
dfs(cnt+1,sum,pick);
dfs(cnt+1,sum*vec[cnt],pick+1);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
ll ans=1;
bool f=1;
for(int i=2;i<=n;i++)
{
if(a[i]==a[i-1])
{
ans=(ans*(m/a[i]))%mod;
continue;
}
if(a[i-1]%a[i]!=0)
{
f=0;
break;
}
prime(a[i-1]/a[i]);
ss=0;
k=m/a[i];
dfs(0,1,0);
ans=(ans*(k-ss))%mod;
}
if(!f)
{
cout<<0<<endl;
continue;
}
cout<<ans<<endl;
}
return 0;
}