1. 程式人生 > 其它 >2022 年 1 月 13 日

2022 年 1 月 13 日

CF27E Number With The Given Amount Of Divisors

即把 \(n\) 分解成 \((k_1+1)(k_2+1)\dots(k_n+1)\) 的形式,配給一些質數作為指數,使得 \(\prod p_i^{k_i}\) 最小。暴力搜尋即可。

有一個小性質:可以發現 \(2\) 一定是最小答案的質因數,且其質因數的指數隨底數的增大而不增。

#include<cstdio>
#include<algorithm>
#include<stack>
int vis[60001], prime[60001], tot, pps[1001]; long long pp[1001][1001];
long long ans = 0x7fffffffffffffffll;
void solve(int i, int n, long long cur) {
	if (cur > ans) return; if (i > 1000) return;
	if (n == 1) return void(ans = cur);
	std::stack<int> lst;
	for (int j = 1; j * j <= n; j++) {
		if (n % j == 0) {
			if (j * j != n && j != 1) lst.push(j);
			int k = n / j - 1;
			if (k > pps[i]) continue;
			if (1e18 / cur <= pp[i][k]) continue;
			solve(i + 1, j, cur * pp[i][k]);
		}
	}
	while (!lst.empty()) {
		int k = lst.top() - 1, j = lst.top(); lst.pop();
		if (k > pps[i]) continue;
		if (1e18 / cur <= pp[i][k]) continue;
		solve(i + 1, n / j, cur * pp[i][k]);
	}
}
int main() {
	for (int i = 2; i <= 60000; i++) {
		if (!vis[i]) prime[++tot] = i;
		for (int j = 1; j <= tot; j++) {
		    int x = prime[j];
			if (i * x > 60000) break;
			vis[i * x] = 1; if (i % x == 0) break;
		}
	}
	for (int i = 1; i <= 1000; i++) {
		pp[i][0] = 1, pp[i][1] = prime[i], pps[i] = 1;
		while (1e18 / pp[i][pps[i]] >= prime[i]) pps[i]++, pp[i][pps[i]] = pp[i][pps[i] - 1] * prime[i];
	}
	int n; scanf("%d", &n), solve(1, n, 1);
	printf("%lld\n", ans);
}

洛谷 P2054 [AHOI2005]洗牌

\(f(x)\) 為處於位置 \(x\) 的數在一次洗牌後的位置。有:

\[f(x)=\begin{cases} 2x&x\leq\frac n2\\ 2\left(x-\frac n2-1\right)+1&x\gt\frac n2 \end{cases} \]

\[f(x)=\begin{cases} 2x&x\leq\frac n2\\ 2x-n-1&x\gt\frac n2 \end{cases} \]

在模 \(n+1\) 意義下可以表示為 \(f(x)\equiv 2x\)。那麼經過 \(m\) 次洗牌後數字 \(x\)

位於 \(2^mx\bmod (n+1)\) 的位置。

則問題轉化成了求方程 \(2^mx\equiv L\pmod{n+1}\) 的最小正整數解。

#include<cstdio>
typedef long long ll;
ll n, m, L;
ll mul(ll x, ll y) {
	__int128 t = ((__int128)x) * y;
	return (ll)(t % (n + 1));
}
ll pow(ll x, ll y) {
	ll ret = 1;
	while (y) {
		if (y & 1) ret = mul(ret, x);
		x = mul(x, x), y >>= 1;
	}
	return ret;
}
ll exgcd(ll a, ll b, ll& x, ll& y) {
	if (!b) return x = 1, y = 0, a;
	ll d = exgcd(b, a % b, y, x);
	return y -= (a / b) * x, d;
}
ll inv(ll a) {
	ll ret = 0, x = 0; exgcd(a, n + 1, ret, x);
	return (ret % (n + 1) + (n + 1)) % (n + 1);
}
int main() {
	scanf("%lld%lld%lld", &n, &m, &L);
	printf("%lld\n", mul(L, inv(pow(2ll, m))));
}