hdu 5514 容斥原理

hdu 5514

题意: 有 n 只青蛙,一开始都在 0 点。有一堆围成一圈的石子,石子的编号是从 0 ~ (m-1)。 所有青蛙只能顺时针跳,每个青蛙可以一次跳a[i]格。问这些青蛙踩过的石子的编号总和是多少?

tags:  容斥经典题。

对 m 分解因子,对每个因子求贡献。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005;

int T, n, m, pp[N], f[N], cnt;
ll  ans;
void get_pp(int mn)
{
    cnt=0;
    for(int i=1; i<=sqrt(mn); ++i)
        if(mn%i==0)
        {
            pp[++cnt]=i;
            if(mn/i != i) pp[++cnt]=mn/i;
        }
    sort(pp+1, pp+1+cnt);
    --cnt;
}
void Init()
{
    mes(f, 0);
    ans = 0;
}
int main()
{
    scanf("%d", &T);
    rep(cas, 1, T)
    {
        scanf("%d%d", &n, &m);
        Init();
        get_pp(m);
        int ai, tmp;
        rep(i,1,n)
        {
            scanf("%d", &ai);
            tmp = __gcd(ai, m);
            rep(j,1,cnt)
                if(pp[j]%tmp==0)
                    f[j] = 1;
        }
        ll  tmp1;
        rep(i,1,cnt)
            if(f[i])
            {
                tmp1 = (m-1)/pp[i];
                ans += tmp1*(tmp1+1)/2 * pp[i] * f[i];
                rep(j,i+1,cnt)
                    if(pp[j]%pp[i]==0)
                        f[j] -= f[i];
            }
        printf("Case #%d: %lld
", cas, ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/sbfhy/p/7800821.html