HDU 5514

来源:互联网 发布:fifaonline3刷ep淘宝 编辑:程序博客网 时间:2024/06/18 15:50

容斥原理。

青蛙跳石头,给出青蛙跳的步数,青蛙所能跳的石头就是第i只青蛙与总步数的最大公因数的倍数,即gcd(a[i], m) * k, k = 0, 1, 2...

这样就会产生重复跳过的石头,用容斥原理来解决。

一开始先用vis[i]来标记所有走过的m的因子,num[i]记录前面的重复数。即最后每一个因子对应的经过个数num[i] - vis[i];

看了好久才懂得。。感觉离散白学了。。。

代码:

#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int a[20005];long long vis[20005];long long num[20005];int x;int n, m;int nn;int gcd(int x, int y){    return y == 0 ? x : gcd(y, x % y);}int main(){    int T;    scanf("%d", &T);    int kase = 0;    while(T--)    {        memset(vis, 0, sizeof(vis));        memset(num, 0, sizeof(num));        scanf("%d%d", &n, &m);        nn = 0;        for(int i = 1; i <= (int)(sqrt(m) + 1); ++i)        {            if(m % i == 0)            {                a[nn++] = i;                a[nn++] = m / i;            }        }        sort(a, a + nn);        nn = unique(a, a + nn) - a;        for(int i = 0; i < n; ++i)        {            int x;            scanf("%d", &x);            int g = gcd(x, m);            for(int j = 0; j < nn; ++j)            if(a[j] % g == 0)            {                vis[j] = 1;            }        }        long long ans = 0;//        vis[nn - 1] = 0;        for(int i = 0; i < nn; ++i)        {            if(vis[i] != 0 || num[i] != 0)            {                long long tmp = m / a[i];                ans += (tmp - 1) * tmp / 2 * a[i] * (vis[i] - num[i]);                tmp = vis[i] - num[i];                for(int j = i + 1; j < nn; ++j)                    if(a[j] % a[i] == 0)                        num[j] += tmp;            }        }        printf("Case #%d: %I64d\n", ++kase, ans);    }}


0 0
原创粉丝点击