HDU - 5514(容斥)

#include <bits/stdc++.h>
using namespace std;
int m,n;
int E;
const int maxn = 1e5;
int a[maxn],factor[maxn],vis[maxn],num[maxn]; /*vis:应该访问的次数;num:当前访问的次数*/
void Init() {
    E = 0;
    memset(factor,0,sizeof(factor));
    memset(vis,0,sizeof(vis));
    memset(num,0,sizeof(num));
}
int gcd(int a,  int b) {
    return b == 0? a: gcd (b,a%b);
}
void GetFactor() { //因数分解
    for(int i = 1 ; i * i <= m ; i++) {
        if(m % i == 0) {
            factor[E++] = i;
            if(i * i != m) {
                factor[E++] = m/i;
            }
        }
    }
    sort(factor,factor+E);
}
void GetVisit() { //判断factor会不会出现访问
    for(int i = 0 ; i < n ; i++) {
        int x = gcd(a[i],m);//当前能访问到的位置的最小下标
        for(int j = 0 ; j < E ; j++) {
            if(factor[j] % x == 0 && factor[j] != m/*注意把下标为m的点排除*/) {
                vis[j] = 1;
            }
        }
    }
}

long long GetValue() { 
    long long  ans = 0;
    for(int  i = 0 ; i < E ; i++) {
        if(vis[i] != num[i]) { // 如果当前计算次数和应该计算的次数相等factor[i]就不会出现在求和里
            long long  t = (m)/factor[i];
            ans += (1+t)*t/2 * factor[i] * (vis[i] - num[i]); 
            // 等差数列求一下和然后乘上    (应该应该访问的次数)与(当前访问的次数)的差  容斥一下
            for(int j = i+1 ; j < E ; j++) { // 把能整除当前facrot的当前访问次数也更新
                if(factor[j] % factor[i] == 0)
                    num[j] += (vis[i] - num[i]);
            }
        }
    }
    return ans;
}
int main() {
    int T;
    cin >> T;
    int kase = 1;
    while(T--) {
        Init();
        cin >> n >> m;
        for(int i = 0 ; i < n ; i++) {
            cin >> a[i];
        }
        GetFactor();
        GetVisit();
        printf("Case #%d: %lld\n",kase++,GetValue());
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值