A - Football Loser

看清总评价的计算公式后利用 structsort 排序即可。

为了避免精度误差,建议按 k=(2m+n)tk=(2m+n)t(将原来的公式除以 0.030.03)计算总评价,此时需要使用 long long。(当然了,直接使用 doublelong double 也是一个不错的选择。)

#include <bits/stdc++.h>
using namespace std;
const int A = 20 + 2;
struct Team
{
	string b;
	int m;
	int n;
	int t;
	long long k;
};
Team team[A];
bool cmp(Team x, Team y)
{
	return x.k > y.k;
}
int main()
{
	freopen("football.in", "r", stdin);
	freopen("football.out", "w", stdout);
	int T;
	cin >> T;
	while (T--)
	{
		int a;
		cin >> a;
		for (int i = 1; i <= a; i++)
		{
			cin >> team[i].b >> team[i].m >> team[i].n >> team[i].t;
			team[i].k = 1ll * team[i].t * (2ll * team[i].m + 1ll * team[i].n);
		}
		sort(team + 1, team + a + 1, cmp);
		for (int i = 1; i <= a; i++)
		{
			cout << team[i].b;
			if (i != a) cout << ' ';
		}
		cout << endl;
	}
	return 0;
}

B - Tangent Dancer

显然 d,φ0d,\varphi \ne 0。考虑一次移动中轨迹的斜率 k=tanφφk=\dfrac{\tan \varphi}{\varphi}。画图可知,当 $\varphi \in (-\dfrac{\pi}{2},0) \cup (0,\dfrac{\pi}{2})$ 时,k(1,+)k \in (1,+\infty)

也就是说,如果直线 ABAB 的斜率 kAB>1k_{AB}>1 且存在,那么就可以从 AA 一次性移动到 BB

很明显,如果我们第一次移动时选择 d=10100,φ=π4d=10^{100},\varphi=\dfrac{\pi}{4},那么一次移动后的位置 XX 与终点 YY 之间的斜率将会极其接近 4π\dfrac{4}{\pi},显然可以从 XX 一次性移动到 YY。整个过程一共移动了 22 次,所以答案总是不超过 22

综上,本题的结论是(设 PP 为起点,QQ 为终点):

  • PPQQ 重合时答案为 00
  • kPQ>1k_{PQ}>1 且存在时答案为 11
  • 以上两个条件都不满足时答案为 22
#include <bits/stdc++.h>
using namespace std;
#define y1 Y1
int steps(int x1, int y1, int x2, int y2)
{
	if (x1 == x2 && y1 == y2) return 0;
	if (x2 > x1 && y2 - y1 > x2 - x1) return 1;
	if (x1 > x2 && y1 - y2 > x1 - x2) return 1;
	return 2;
}
int main()
{
	freopen("tangent.in", "r", stdin);
	freopen("tangent.out", "w", stdout);
	int x1, y1, x2, y2;
	cin >> x1 >> y1 >> x2 >> y2;
	cout << steps(x1, y1, x2, y2) << endl;
	return 0;
}

C - Lottery Cheater

由题意可以列出一个 nn 元异或方程组,且每个方程中只有 22 个未知数。直接钦定任意一个值后用代入法递归解方程即可。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 12;
bool ok[N], ans[N];
int n, k;
string s;
void fill(int i)
{
	if (ok[i]) return;
	ok[i] = true;
	int next = (i + k) % n;
	ans[next] = ans[i] ^ (s[next] - '0');
	fill(next);
}
int main()
{
	freopen("lottery.in", "r", stdin);
	freopen("lottery.out", "w", stdout);
	cin >> n >> k >> s;
	reverse(s.begin(), s.end());
	k %= n;
	for (int i = 0; i <= n - 1; i++)
		fill(i);
	for (int i = n - 1; i >= 0; i--)
		putchar(ans[i] + '0');
	return 0;
}

D - Factorial Master

首先特判 n2n \le 2 的情况。

很明显,当 xnx \ge n 时,nx!n\mid x!,因此答案不可能大于 n1n-1

nn 为质数时,由威尔逊定理可得:

(n1)!1 (mod n)(n-1)! \equiv -1\ (\bmod\ n) (n1)!n1 (mod n)(n-1)! \equiv n-1\ (\bmod\ n) (n2)!1 (mod n)(n-2)! \equiv 1\ (\bmod\ n)

因此答案一定是 n2n-2

nn 为合数时,由题意可知 px!p\nmid x!,其中 ppnn 的最小素因子。

显然 pnp \le \sqrt{n},并且答案不大于 p1p-1,暴力枚举即可。

最终的时间复杂度是 O(Tn)O(T\sqrt{n})

#include <bits/stdc++.h>
using namespace std;
bool prime(int n)
{
	if (n == 1) return false;
	for (int i = 2; i * i <= n; i++)
		if (n % i == 0) return false;
	return true;
}
int solve(int n)
{
	if (n <= 2) return n - 1;
	if (prime(n)) return n - 2;
	long long f = 1;
	int ans = 1;
	for (int i = 2; n % i != 0; i++)
	{
		f = f * i % n;
		if (f == 1) ans = i;
	}
	return ans;
}
int main()
{
	freopen("factorial.in", "r", stdin);
	freopen("factorial.out", "w", stdout);
	int T;
	cin >> T;
	while (T--)
	{
		int n;
		cin >> n;
		cout << solve(n) << endl;
	}
	return 0;
}