HDU 5514 Frogs(容斥原理 gcd)

来源:互联网 发布:华云数据集团有限公司 编辑:程序博客网 时间:2024/05/01 03:10

题意:

有n个青蛙,一开始都在0点,然后有m个石子圈成一圈的石子,石子的编号是从0-m-1的然后青蛙只能顺时针跳,每个青蛙可以一次跳a[i]格,然后所有青蛙都这样一直跳下去然后问你,这些青蛙踩过的石子的编号和是多少?

思路:

啊我这只弱鸡,,,只能照着大神的思路写下来,,然后就基本一样了。。。
对与第i只青蛙,它必然会跳到 d=kgcd(a[i],m) 这个位置上,
(可以通过列模线性方程的有解条件得到(贝祖定理))
如果直接暴力枚举的话显然会超时。所以需要换种思路,通过观察上式我们发现,
d一定是m的因子,所以我们就可以通过枚举m的所有因子来找到所有间隔d。
然后从m的第一个因子开始计数,同时记录这个数对之后他的倍数的影响,
如果这里加多了,后边的位置就要相应加上,好方便之后减去。(容斥原理)

#include <cstdio>#include <iostream>#include <cmath>#include <algorithm>#include <string.h>typedef long long int lli;using namespace std;int vis[100100];int factor[100100];int num[100100];lli gcd(lli a,lli b){    return b==0? a:gcd(b,a%b);}int main(){    int t;    cin>>t;    int n,m;    int cas = 0;    while(t--){        memset(num,0,sizeof(num));        memset(vis,0,sizeof(vis));        cas++;        int cnt = 0;        scanf("%d%d",&n,&m);        lli temp = sqrt(m);        for(int i = 1;i <= temp;i++){            if(m % i == 0){                factor[cnt++] = i;                if(i * i != m){                    factor[cnt++] = m/i;                }            }        }        sort(factor,factor+cnt);        for(int i = 0;i < n;i++){            scanf("%I64d",&temp);            temp = gcd(temp,m);            for(int j = 0;j < cnt;j++){                if(factor[j] % temp == 0){                    vis[j] = 1;                }            }        }        vis[cnt-1] = 0;        lli ans = 0;        m -= 1;        for(int i = 0;i < cnt-1;i++){            if(num[i] != vis[i]){                temp = m/factor[i];                // factor[i] * (temp+1) * temp/2 是等差数列求和                ans += factor[i] * (temp+1) * temp/2 * (vis[i]-num[i]);                temp = vis[i] - num[i];// 关键                for(int j = i;j < cnt-1;j++){                    if(factor[j] % factor[i] == 0){                        num[j] += temp;//关键                    }                }            }        }        printf("Case #%d: %I64d\n",cas,ans);    }    return 0;}
0 0