HDU 5668 Circle

中国剩余定理。

可以手动模拟一下每一次开始的人的编号和结束的人的编号。

每次删掉一个人,对剩下的人重新编号。

这样一次模拟下来,可以得到n个方程

形如:(u[i]+k)%(n-i+1)=v[i]

化简一下就是:k%(n-i+1)=v[i]-u[i]%(n-i+1)

接下来就是求解最小的k,满足所有式子

中国剩余定理板子一套就AC了......

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn = 30;
int n, T;
int s[maxn], flag[maxn], tmp[maxn];

int u[30], v[30];
LL a[maxn], b[maxn];

void ls()
{
    int cnt = 1;
    for (int i = 1; i <= n; i++)
    {
        if (flag[i] == 0)
            tmp[cnt++] = i;
    }
}

int Find(int a)
{
    for (int i = a; i <= n; i++)
        if (flag[i] == 0) return i;
    for (int i = 1; i <= a; i++)
        if (flag[i] == 0) return i;
}

int f2(int a)
{
    for (int i = 1;; i++)
        if (tmp[i] == a) return i;
}

void egcd(LL a, LL b, LL&d, LL&x, LL&y)
{
    if (!b) { d = a, x = 1, y = 0; }
    else
    {
        egcd(b, a%b, d, y, x);
        y -= x*(a / b);
    }
}

LL lmes() {
    LL M = a[1], R = b[1], x, y, d;
    for (int i = 2; i <= n; i++) {
        egcd(M, a[i], d, x, y);
        if ((b[i] - R) % d) return -1;
        x = (b[i] - R) / d*x % (a[i] / d);
        R += x*M;
        M = M / d*a[i];
        R %= M;
    }
    return (R + M) % M ? (R + M) % M : M;
}

void exgcd(LL a, LL b, LL &d, LL &x, LL &y)
{
    if (b == 0)
        d = a, x = 1, y = 0;
    else
    {
        exgcd(b, a%b, d, y, x);
        y -= x * (a / b);
    }
}

LL china(LL n, LL m[], LL a[])
{
    LL aa = a[0];
    LL mm = m[0];
    for (int i = 0; i<n; i++)
    {
        LL sub = (a[i] - aa);
        LL d, x, y;
        exgcd(mm, m[i], d, x, y);
        if (sub % d) return -1;

        LL new_m = m[i] / d;
        new_m = (sub / d*x%new_m + new_m) % new_m;
        aa = mm*new_m + aa;
        mm = mm*m[i] / d;
    }
    aa = (aa + mm) % mm;
    return aa ? aa : mm;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            int ai; scanf("%d", &ai);
            s[ai] = i;
        }
        memset(flag, 0, sizeof flag);

        u[1] = 0, v[1] = s[1];
        if (v[1] == n) v[1] = 0;

        flag[s[1]] = 1;

        for (int i = 2; i <= n; i++)
        {
            int st, en;
            ls();
            st = Find(s[i - 1]), st = f2(st), st = st - 1;
            if (st == -1) st = n - i;
            en = f2(s[i]), u[i] = st;
            v[i] = en; if (v[i] == n - i+1) v[i] = 0;
            flag[s[i]] = 1;
        }
        /*
        for (int i = 1; i <= n; i++)
            printf("%d %d\n", u[i], v[i]);
        */

        //接下来就是求解最小的k,满足所有式子
        //k%(n-i+1)=v[i]-u[i]%(n-i+1)

        for (int i = 1; i <= n; i++)
        {
            a[i] = (LL)(n - i + 1);
            b[i] = (LL)(v[i] - u[i] % (n - i + 1));
        }
        LL k = china(n, a + 1, b + 1);
        if (k == -1) printf("Creation August is a SB!\n");
        else printf("%lld\n", k);
    }
    return 0;
}

 

posted @ 2016-04-17 10:12  Fighting_Heart  阅读(307)  评论(0编辑  收藏  举报