大意:








欧拉函数求和+思维














#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4+10;
ll com[maxn];
ll t,n,m,ans;
ll euler(ll x) {
    ll ans = x;
    for (ll i = 2; i * i <= x; ++i) {
        if (x % i == 0) {
            ans = ans / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    }
    if (x != 1) ans = ans / x * (x - 1);
    return ans;
}
bool check(ll x) {
    for(int i = 0; i < n; i++)
        if(x%com[i] == 0)
            return true;
    return false;
}
int main() {
    cin>>t;
    for(ll cas=1;cas<=t;++cas,ans=0) {
        bool Prime = false;
        cin>>n>>m;
        for(ll i=0,x,g;i<n;++i) {
            cin>>x;
            com[i]=__gcd(x,m);
            if(com[i] == 1) Prime = true;
        }
        if(Prime) ans = m*(m-1)/2;
        else {
            for(int i = 2; i*i <= m; i++) if(m%i == 0){
                if(check(i)) ans += euler(m/i)*m/2;
                if(i*i!=m && check(m/i)) ans+= euler(i)*m/2;
            }
        }
        printf("Case #%lld: %lld\n",cas,ans);
    }
}

容斥原理









#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<ll>v;
const int maxn=1e5+5;
ll cnt[maxn],sum[maxn];
int main(void) {
    ll t,n,m;
    cin>>t;
    for(int cas=1;cas<=t;++cas) {
        cin>>n>>m;
        memset(cnt,0,sizeof cnt);
        memset(sum,0,sizeof sum);
        v.clear();
        for(int i=2;i*i<m;++i) if(m%i==0) {
            v.push_back(i);
            v.push_back(m/i);
        }
        v.push_back(1);
        sort(v.begin(),v.end());
        for(ll i=1,x,g;i<=n;++i) {
            cin>>x;
            g=__gcd(x,m);
            for(int j=0;j<v.size();++j) if(v[j]%g==0)
                cnt[j]=1;
        }
        ll res=0;
        for(int i=0;i<v.size();++i) {
            res+=m*(m/v[i]-1)/2*(cnt[i]-sum[i]);
            for(int j=i+1;j<v.size();++j) {
                if(v[j]%v[i]==0) sum[j]+=cnt[i]-sum[i];
            }
        }
        printf("Case #%lld: %lld\n",cas,res);
    }
}