D. Count GCD(分解质因数、容斥)

分析题意易得当当a[i]无法整除a[i+1]时无解。

再进一步分析构造数组时我们只需要保证\gcd (a[i-1],b[i])=a[i],可以将式子转化为

\gcd (a[i-1]/a[i],b[i]/a[i])=1,则本题转化为在1到b[i]/a[i]中有几个数与a[i-1]/a[i]互质。

因为b[i]的上界是m,所以也就是1到m/a[i]中有几个数与a[i-1]/a[i]互质。到这里这个题目还是比较困难,我们进一步转化,将a[i-1]/a[i]的质因子分解出来,我们易知每一个质因子都能被1到 max(m/a[i])中的某些数整除,设这个质因子是x,则1到max中能被整除x的数有max/x个。我们容斥记下数,这些数就是1到max中所有至少被a[i-1]/a[i]的一个质因子整除的数的个数,也就是说这些数和a[i-1]/a[i]至少含有一个质因子,那么剩下的数就是和a[i-1]/a[i]互质的数,根据乘法原理,累乘即是正确答案。

#include <iostream>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<cmath>
#include<queue>
#include<bitset>
#include<vector>
#include<map>
#include<unordered_map>
#define int long long
#define endl '\n'
#define lowbit(x) (x &-x)
#define mh(x) memset(x, -1, sizeof h)
#define debug(x) cerr << #x << "=" << x << endl;
#define brk exit(0);
using namespace std;
void inline TLE() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
const int N = 2e5 + 10;
const int M = 2 * N;
const int mod = 998244353;
const double esp = 1e-13;
const double pi = acos(-1);
typedef pair<int, int> PII;
typedef long long ll;
int n, m;
vector<int>fac;
void gpf(int n) {
    fac.clear();
    for (int i = 2;i <= n / i;i++) {
        if (n % i == 0) {
            while (n % i == 0) {
                n /= i;
            }
            fac.push_back(i);
        }
    }
    if (n>1)fac.push_back(n);
}
void sub_mod(int &x, int y) {
	ll res = 1LL * x % mod - (y % mod);
	x= (res + mod) % mod;
}
void add_mod(int &x, int y) {
    x= (1LL * x + y) % mod;
}
int work(int t, int r) {
    vector<int>v;
    for (auto it : fac) {
        if (t % it == 0) {
            v.push_back(it);
        }
    }
    
    int ans = 0, idx = v.size();
    for (int i = 0;i < (1ll << idx);i++) {
        int res = 1, cnt = 0;
        for (int j = 0;j < idx;j++) {
            if (i &(1<<j)) {
                res *= v[j];
                cnt++;

            }
        }
        if (cnt & 1)sub_mod(ans, r / res);
        else add_mod(ans, r / res);
    }
    return ans;
}


int a[N];
void solve() {
    cin >> n >> m;
    for (int i = 1;i <= n;i++)cin >> a[i];
    for (int i = 1;i < n;i++) {
        if (a[i] % a[i+1]) {
            cout << 0 << endl;
            return;
        }
    }
    gpf(a[1]);
    int res = 1;
    for (int i = 1;i < n;i++) {
        int t1 = a[i] / a[i + 1];
        int t2 = m / a[i + 1];
        res = res * work(t1, t2);
        res %= mod;
    }
    cout << res << endl;
}
signed main() {
    int t;cin >> t;
    while (t--)
        solve();
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值