0603模拟赛 解码 排列 安排

A 解码

题囬

0603模拟赛 解码 排列 安排_第1张图片
在这里插入图片描述在这里插入图片描述0603模拟赛 解码 排列 安排_第2张图片

题解

x c ≡ m   ( m o d   n ) x^c\equiv m\ (mod\ n) xcm (mod n),且 c c c ( p − 1 ) ⋅ ( q − 1 ) (p-1)\cdot (q-1) (p1)(q1)互质。

发现 φ ( n ) = ( p − 1 ) ⋅ ( q − 1 ) \varphi(n)=(p-1)\cdot(q-1) φ(n)=(p1)(q1),又 x φ ( n ) ≡ 1   ( m o d   n ) x^{\varphi(n)}\equiv1\ (mod\ n) xφ(n)1 (mod n)

那么一定存在一个 t t t使得 c ⋅ t ≡ 1   ( m o d   φ ( n ) ) c\cdot t\equiv1\ (mod\ \varphi(n)) ct1 (mod φ(n)),这个 t t t可以通过 e x g c d exgcd exgcd求出。

那么 x c ⋅ t ≡ x 1 ≡ m t   ( m o d   n ) x^{c\cdot t}\equiv x^1\equiv m^t\ (mod\ n) xctx1mt (mod n)。所以直接快速幂就求出了答案。

问题是我们不知道 p , q p,q p,q。如果直接 p o l l a r d   r h o pollard\ rho pollard rho只有30分。

所以我考试时就只拿了30分。

发现还有一个条件没有用到 q − p ≤ 3 e 5 q-p\le 3e5 qp3e5。我们假设 q = p + d q=p+d q=p+d d d d为正整数且小于 3 e 5 3e5 3e5

列出一个方程 p ( p + d ) = n p(p+d)=n p(p+d)=n

解得 p = d 2 + 4 n − d 2 p=\frac{\sqrt{d^2+4n}-d}2 p=2d2+4n d

在前三个子任务中有 p , q p,q p,q之间无其他质数,所以 d d d很小,直接枚举。

最后一个子任务没有这个限制,但是发现 p ≥ 2 e 9 p\ge2e9 p2e9,也就是 n ≥ 4 e 18 n\ge 4e18 n4e18

我们设 k = d 2 + 4 n k=\sqrt{d^2+4n} k=d2+4n ,所以 k 2 = d 2 + 4 n k^2=d^2+4n k2=d2+4n。如果要枚举 k k k,下界就是 2 n 2\sqrt{n} 2n 。这样的话我们发现 k k k没增加 1 1 1 k 2 k^2 k2会增加 1 e 9 1e9 1e9级别的值。又 d ≤ 3 e 5 , d 2 ≤ 9 e 10 d\le 3e5,d^2\le9e10 d3e5,d29e10,那么 k k k也只会枚举十几次。

那么我们就做完了。

CODE

#include 
using namespace std;
typedef long long LL;
inline LL mul(LL a, LL b, LL p) {
	LL re = a * b - (LL)((long double)a/p*b + 0.5) * p;
	return re < 0 ? re + p : re;
}
inline LL qpow(LL a, LL b, LL c) {
	LL re = 1; a %= c;
	for(; b; b>>=1, a=mul(a, a, c))if(b&1)re=mul(re, a, c);
	return re;
}
LL mysqrt(LL n) {
	if(n < 0) return -1;
	LL sq = round(sqrt(n));
	if(sq * sq == n) return sq;
	return -1;
}
LL solve(LL n) {
	LL p;
	if(n <= 1e9) {
		for(LL d = 1, k; ; ++d)
			if(~(k=mysqrt(d*d + 4*n))) {
				p = (k - d) / 2;
				return (p-1) * (p+d-1);
			}
	}
	else {
		for(LL k = 2*sqrt(n), d; ; ++k)
			if(~(d=mysqrt(k*k - 4*n))) {
				p = (k - d) / 2;
				return (p-1) * (p+d-1);
			}
	}
}
void exgcd(LL a, LL b, LL &x, LL &y) {
	if(!b) { x = 1; y = 0; return; }
	exgcd(b, a%b, y, x); y -= x*(a/b);
}
LL n, m, c;
int main () {
	freopen("rsa.in", "r", stdin);
	freopen("rsa.out", "w", stdout);
	int T; scanf("%d", &T); while(T--) {
		scanf("%lld%lld%lld", &n, &m, &c);
		LL x, y, phi = solve(n);
		exgcd(c, phi, x, y); x = (x % phi + phi) % phi;
		x = qpow(m, x, n);
		printf("%lld\n", x);
	}
}

这里没有太考虑longlong乘起来炸了的情况(能过就行),否则可以把分母的2放进根号里什么的来减小数字运算的大小。


B 排列

题囬

0603模拟赛 解码 排列 安排_第3张图片在这里插入图片描述0603模拟赛 解码 排列 安排_第4张图片0603模拟赛 解码 排列 安排_第5张图片

题解

0603模拟赛 解码 排列 安排_第6张图片0603模拟赛 解码 排列 安排_第7张图片

CODE

#include 
using namespace std;
#define x first
#define id second
typedef double db;
typedef pair<db,int> pr;
const int MAXN = 505;
const db eps = 1e-12;
int n, m, ans[MAXN][MAXN];
db val[MAXN], b[MAXN];
pr a[MAXN];
int main () {
	//freopen("permutation.in", "r", stdin);
	//freopen("permutation.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1, y; i <= n; ++i) scanf("%d", &y), a[i] = pr(y, i);
	sort(a + 1, a + n + 1); int s = 0;
	for(int i = 1; i <= n; ++i) if((s += (int)round(a[i].x)) < i*(i+1)/2) return puts("-1"), 0;
	if(s != n*(n+1)/2) return puts("-1"), 0;
	db now = 1;
	for(int i = 1; i <= n && now > eps; ++i) {
		sort(a + 1, a + n + 1);
		db l = 0, r = now, mid, sum;
		while(r-l > 1e-10) {
			mid = (l + r) / 2; sum = 0;
			bool flg = 1;
			for(int j = 1; j <= n && flg; ++j) {
				if(a[j].x + eps < mid * j) flg = 0;
				b[j] = a[j].x - mid * j;
			}
			sort(b + 1, b + n + 1);
			for(int j = 1; j <= n && flg; ++j)
				if((sum += b[j]) + eps < (now-mid)*j*(j+1)/2) flg = 0;
			if(flg) l = mid;
			else r = mid;
		}
		now -= (val[++m] = l);
		for(int j = 1; j <= n; ++j)
			ans[m][a[j].id] = j, a[j].x -= l * j;
	}
	printf("%d\n", m);
	for(int i = 1; i <= m; ++i, puts("")) {
		printf("%.12f", val[i]);
		for(int j = 1; j <= n; ++j)
			printf(" %d", ans[i][j]);
	}
}

C 安排

题囬

0603模拟赛 解码 排列 安排_第8张图片0603模拟赛 解码 排列 安排_第9张图片在这里插入图片描述0603模拟赛 解码 排列 安排_第10张图片

题解

0603模拟赛 解码 排列 安排_第11张图片

CODE

咕咕咕

你可能感兴趣的:(模拟赛题解)