P5944 出圈游戏 题解

传送门

看一个人什么时候出圈没有用。先求一个数组 \(id[i]\) 表示第 \(i\) 个出圈的是谁。

考虑第 \(i\) 个出圈的人,应该是从 \(id[i-1]+1\) 开始绕了若干圈,最后从 \(id[i-1]+1\) 走到 \(id[i]\) 的。

也就是 \(K\equiv dist(id[i-1]+1,id[i])\pmod {n-i+1}\)。这里 \(dist(id[i-1]+1,id[i])\) 表示从 \(id[i-1]+1\) 逆时针走到 \(id[i]\) 会经过多少个没出圈的人。

于是得到了 \(n\) 个同余方程组,要求最小正整数解。用 EXCRT 求解即可。注意如果答案为 \(0\),应输出 EXCRT 最终得到的模数。

点击查看代码
#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 5;

inline long long read()
{
    long long x=0,f=1;
    char ch;
    while(ch>'9'||ch<'0')
    {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}                
inline void write(long long x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>=10)write(x/10);
    putchar(x%10+'0');
}
typedef pair<long long, long long> pii;
queue<pii> q;
void exgcd(long long a, long long b, long long &x, long long &y) {
	if (b == 0) {
		x = 1, y = 0;
		return ;
	}
	exgcd(b, a % b, x, y);
	long long x0 = x, y0 = y;
	x = y0;
	y = x0 - (a / b) * y0;
	return ;
}
long long gcd(long long a, long long b) {
	if (b == 0)
		return a;
	return gcd(b, a % b);
}
long long lcm(long long a, long long b) {
	return a * b / gcd(a, b);
}
void chk() {
	pii f1 = q.front();
	q.pop();
	pii f2 = q.front();
	q.pop();
	long long p1 = f1.first, m1 = f1.second, p2 = f2.first, m2 = f2.second;
//	write(p1);
//	putchar(' ');
//	write(m1);
//	putchar(' ');
//	write(p2);
//	putchar(' ');
//	write(m2);
//	putchar('\n');
	if ((p2 - p1) % gcd(m1, m2) != 0) {
		cout << "NIE\n";
		exit(0);
	}
	long long g = gcd(m1, m2), A, B;
	exgcd(m1 / g, m2 / g, A, B);
	long long t = (p1 + (p2 - p1) / g * A * m1 % lcm(m1, m2)) % lcm(m1, m2);
	if (t >= 0)
		q.push(make_pair(t, lcm(m1, m2)));
	else {
		t += lcm(m1, m2);
		q.push(make_pair(t, lcm(m1, m2)));
	}
}

int n;
int rk[N], id[N];
long long a[N], b[N];
bool out[N] = {};

int nxt(int x) {
	if (x == n)
		return 1;
	return x + 1;
}

int main() {
//	freopen("1.in", "r", stdin);
//	freopen("1.out", "w", stdout);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> rk[i];
		id[rk[i]] = i;
	}
	for (int i = 1, p = 0; i < n; i++) {
		int cnt = 0;
		while (p != id[i]) {
			p = nxt(p);
			if (!out[p])
				cnt++;
		}
		out[p] = true;
		a[i] = cnt % (n - i + 1), b[i] = n - i + 1;
//		write(a[i]);
//		putchar(' ');
//		write(b[i]);
//		putchar('\n');
	}	
	
	for (int i = 1; i < n; i++)
		q.push(make_pair(a[i], b[i]));
	for (int i = 1; i < n - 1; i++)
		chk();
	if (q.front().first == 0)
		write(q.front().second);
	else
		write(q.front().first);
	return 0; 
}
posted @ 2024-03-06 22:42  FLY_lai  阅读(10)  评论(0编辑  收藏  举报