Loading

技巧和杂项

图论

同余最短路

用于一些值域较大的判定性 / 解计数 / 最值问题。

通常选定一个模数,然后考虑在模数意义下的每个剩余类,可以设出类似于 \(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;
}
posted @ 2022-11-04 10:27  kymru  阅读(69)  评论(0编辑  收藏  举报