有 x c ≡ m ( m o d n ) x^c\equiv m\ (mod\ n) xc≡m (mod n),且 c c c与 ( p − 1 ) ⋅ ( q − 1 ) (p-1)\cdot (q-1) (p−1)⋅(q−1)互质。
发现 φ ( n ) = ( p − 1 ) ⋅ ( q − 1 ) \varphi(n)=(p-1)\cdot(q-1) φ(n)=(p−1)⋅(q−1),又 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)) c⋅t≡1 (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) xc⋅t≡x1≡mt (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 q−p≤3e5。我们假设 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 p≥2e9,也就是 n ≥ 4 e 18 n\ge 4e18 n≥4e18。
我们设 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 d≤3e5,d2≤9e10,那么 k k k也只会枚举十几次。
那么我们就做完了。
#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放进根号里什么的来减小数字运算的大小。
#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]);
}
}
咕咕咕