ACM学习历程—HDU5668 Circle(数论)

http://acm.hdu.edu.cn/showproblem.php?pid=5668

这题的话,假设每次报x个,那么可以模拟一遍,

假设第i个出局的是a[i],那么从第i-1个出局的人后,重新报数到他假设经过了p个人,

那么自然x = k(n-i)+p(0<= i < n)

即x = p (mod n-i)

然后显然可以得到n个这样的方程,于是就是中国剩余定理了。

 

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long

using namespace std;

int n, s[25];
bool vis[25];
LL rest[25], mmod[25];

LL gcd(LL a, LL b)
{
    LL r;
    while (b != 0)
    {
        r = b;
        b = a%b;
        a = r;
    }
    return a;
}

LL lcm(LL a, LL b)
{
    return a/gcd(a, b)*b;
}

//EXGCD
//求解方程ax+by=d,即ax=d mod(b)
//扩展可求逆元
//O(logn)
void exgcd(LL a, LL b, LL &x, LL &y, LL &d)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        d = a;
    }
    else
    {
        exgcd(b, a%b, y, x, d);
        y -= a/b*x;
    }
}

//中国剩余定理(非互质)
//其中a为除数数组,n为模数数组
LL inv(LL a, LL n)
{
    LL x, y, d;
    exgcd(a, n, x, y, d);
    if (d != 1)
        return -1;
    return (x%n + n) % n;
}

bool Merge(LL a1, LL n1, LL a2, LL n2, LL &aa, LL &nn)
{
    LL d = gcd(n1, n2);
    LL c = a2 - a1;
    if (c % d)
        return false;
    //(n1/d)*k1 = (c/d)(mod(n2/d))
    c /= d;
    n1 /= d;
    n2 /= d;
    //k1 = (c/d)*(n1/d)^(-1)(mod(n2/d))
    c *= inv(n1, n2);
    c %= n2;//k1
    c *= n1 * d;//a = n1*k1+a1
    c += a1;
    nn = n1*n2*d;
    aa = c;
    return true;
}

LL CRT(int len, LL *a, LL *n)
{
    LL a1 = a[0], n1 = n[0];
    LL a2, n2;
    for (int i = 1; i < len; i++)
    {
        LL aa, nn;
        a2 = a[i], n2 = n[i];
        if (!Merge(a1, n1, a2, n2, aa, nn))
            return -1;
        a1 = aa;
        n1 = nn;
    }
    return (a1%n1 + n1) % n1;
}

void work()
{
    LL ans, tmp = 1;
    memset(vis, false, sizeof(vis));
    int now = 0, step, t = 0;
    for (int i = 0; i < n; ++i)
    {
        step = 0;
        for (int j = t%n; j < n; j = (j+1)%n)
        {
            if (vis[j]) continue;
            step++;
            if (j == s[now])
            {
                now++;
                vis[j] = true;
                rest[i] = step%(n-i);
                mmod[i] = n-i;
                tmp = lcm(tmp, n-i);
                t = j;
                break;
            }
        }
    }
    ans = CRT(n, rest, mmod);
    if (ans == -1)
        printf("Creation August is a SB!\n");
    else
    {
        ans = (ans%tmp+tmp)%tmp;
        if (ans == 0) ans = tmp;
        cout << ans << endl;
    }
}

int main()
{
    //freopen("test.in", "r", stdin);
    int T, u;
    scanf("%d", &T);
    for (int times = 1; times <= T; ++times)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &u);
            s[u-1] = i;
        }
        work();
    }
    return 0;
}
View Code

 

posted on 2016-04-24 19:36  AndyQsmart  阅读(461)  评论(0编辑  收藏  举报

导航