技巧和杂项
图论
同余最短路
用于一些值域较大的判定性 / 解计数 / 最值问题。
通常选定一个模数,然后考虑在模数意义下的每个剩余类,可以设出类似于 \(f[i]\) 表示第 \(i\) 个剩余类的答案一类的状态。
然后考虑将第 \(i\) 个剩余类抽象成点,剩余类之间的转移关系抽象成边,通过最短路计算该剩余类的最小合法解得到该剩余类的合法范围。
于是变成了一个图论问题。
杂项
高维前缀和(sosdp)
求一类子集和问题或者偏序问题。
求 \(f[i]\) 表示所有 \(i\) 的子集的和
for (int j = 0; j < n; j++)
for (int i = 1; i < (1 << n); i++)
if (i & (1 << j)) f[i][j] += f[i][j ^ (1 << j)];
求 \(f[i]\) 表示 \(i\) 的所有超集的和
for (int j = 0; j < n; j++)
for (int i = 0; i < (1 << n); i++)
if (!(i & (1 << j))) f[i] += f[i ^ (1 << j)];
可以同理得到高维前缀 \(\min, \max\) 等。
01 分数规划
已知有 \(n\) 个物品,每个物品有两个属性 \(a, b\)。试选出若干物品 \(p_1, ..., p_m\),使得 \(\frac{\sum\limits_{i = 1}^m a_{p_i}}{\sum\limits_{i = 1}^m b_{p_i}}\) 取最大值。
考虑先加上 \(m \geq k\) 的限制,其中 \(k\) 是任意自然数。
记最终的结果为 \(ans\)。令 \(sa = \sum\limits_{i = 1}^m a_{p_i}, sb = \sum\limits_{i = 1}^m b_{p_i}\),那么有 \(\frac{sa}{sb} \leq ans\),整理得 \(sa - ans \cdot sb \leq 0\)
上式实际上等价于 \(\sum\limits_{i = 1}^m a_{p_i} - (b_{p_i} - ans) \leq 0\),也就是把整体贡献转化成单个物品的贡献。
于是可以考虑取 \(a_i - b_i - ans\) 最小的前 \(m\) 个元素计算贡献即可。
三分
适用于对单峰 / 单谷函数求近似最值的情况。
考虑将区间 \([l, r]\) 分成三份 \([l, k_1], (k_1, k_2), [k_2, r]\),根据函数在 \(k_1, k_2\) 处取值的大小关系判断极点的位置。
单峰函数的判定可以考虑打表或者感性证明,反正我是不会数学方法。
Pollard-rho
大数质因数分解。
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <algorithm>
using namespace std;
typedef long long ll;
int t;
ll mxf, n;
ll gcd(ll a, ll b) { return (!b ? a : gcd(b, a % b)); }
ll qpow(ll base, ll power, ll mod)
{
ll res = 1;
while (power)
{
if (power & 1) res = (__int128) res * base % mod;
base = (__int128) base * base % mod, power >>= 1;
}
return res;
}
bool MR(ll p)
{
if (p < 2) return false;
if (p == 2) return true;
if (p == 3) return true;
ll d = p - 1, r = 0;
while (!(d & 1)) d >>= 1, r++;
for (ll k = 0; k < 10; k++)
{
ll a = rand() % (p - 2) + 2, x = qpow(a, d, p);
if ((x == 1) || (x == p - 1)) continue;
for (int i = 0; i < r - 1; i++)
{
x = (__int128) x * x % p;
if (x == p - 1) break;
}
if (x != p - 1) return false;
}
return true;
}
ll PR(ll x)
{
ll s = 0, t = 0;
ll c = (ll) rand() % (x - 1) + 1;
int stp = 0, g = 1;
ll val = 1;
for (g = 1; ; g <<= 1, s = t, val = 1)
{
for (stp = 1; stp <= g; stp++)
{
t = ((__int128) t * t + c) % x;
val = (__int128) val * abs(t - s) % x;
if (stp % 127 == 0)
{
ll d = gcd(val, x);
if (d > 1) return d;
}
}
ll d = gcd(val, x);
if (d > 1) return d;
}
}
void fac(ll x)
{
if ((x <= mxf) || (x < 2)) return;
if (MR(x)) return mxf = max(mxf, x), void();
ll p = x;
while (p >= x) p = PR(x);
while (x % p == 0) x /= p;
fac(x), fac(p);
}
int main()
{
scanf("%d", &t);
while (t--)
{
srand((unsigned) time(0));
mxf = 0;
scanf("%lld", &n);
fac(n);
if (mxf == n) puts("Prime");
else printf("%lld\n", mxf);
}
return 0;
}