DontKnowWhatToSay

FBI WARNING: 以下内容为我的随机发言,没有一句是人话。

以下内容按形容词归类:


指数取模不要用 \(\bmod\)


奇怪的 RE 可能是爆栈,记得 \(\texttt{ulimit -s}\)


奇怪东西

[ABC306G] Return to 1
without sol:

???

\(10^{10^{100}}\) 大的离谱,只要凑出一条能回到1的路径,长度为 \(x = 2^{p_1} \times 5^{p_2}\)

容易注意到该条件等价于所有从1出发后回到1的环的 \(\gcd = 2^{p_1} \times 5^{p_2}\)

问题回到如何数环,如果极限构造至少有 \(\frac{m}{2}\) 个环,数不完。

how to deal with?

with sol:

\(|dep_u + 1 - dep_v|\)


无用东西

[CF961G] Partitions

without sol:

容易想到一个柿子

\[ans = \sum_{i = 1}^{n} w_i \sum_{s = 1}^{n} s \binom{n - 1}{s - 1}{n - s\brace k - 1} \]

后面的部分拆出来

\[\sum_{s = 1}^{n} s \binom{n - 1}{s - 1}{n - s\brace k - 1} \]

带入斯特林数通项公式

\[\sum^n_{s = 1} s \binom{n - 1}{s - 1} \sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}t^{n - s}}{t!(k - t - 1)!} \]

后面的不太好做,但前面的形式挺不错的

\[\sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}}{t!(k - t - 1)!} \sum^n_{s = 1} s \binom{n - 1}{s - 1}t^{n - s} \]

\[\binom{n}{m} = \frac{n!}{m!(n - m)!} \]

\(s\)\(s - 1\)\(1\) 试着拼一下把 \(s\) 换出来

\[\sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}}{t!(k - t - 1)!} \sum^n_{s = 1}\left(\binom{n - 1}{s - 1}t^{n - s} + (s- 1) \binom{n - 1}{s - 1}t^{n - s}\right) \]

\[\sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}}{t!(k - t - 1)!} \left(\left(\sum^n_{s = 1}\binom{n - 1}{s - 1}t^{n - s}\right) + \left(\sum^n_{s = 1}(s- 1) \binom{n - 1}{s - 1}t^{n - s}\right)\right) \]

\[\sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}}{t!(k - t - 1)!} \left(\left(\sum^n_{s = 1}\binom{n - 1}{s - 1}t^{n - s}\right) + (n - 1)\left(\sum^n_{s = 1} \binom{n - 2}{s - 2}t^{n - s}\right)\right) \]

组合数不好算,但是幂好算,发现两个式子都是二项式定理的结构,配个 \(1\) 凑出来

\[\sum^{k - 1}_{t = 0}\frac{(-1)^{k - t - 1}}{t!(k - t - 1)!} \left((t + 1)^{n - 1} + (n - 1) (t + 1)^{n - 2}\right) \]

剩下的都很好算,幂次为负数时特判一下

code

ll Pow(ll a, ll b, ll mod) {
    if(b < 0) return Pow(Pow(a, -b, mod), mod - 2, mod);
    ll res = 1;
    while(b) {
        if(b & 1)
            res = res * a % mod;
        a = a * a % mod, b >>= 1;
    }
    return res;
}
const int mod = 1e9 + 7;
const int maxk = 2e5 + 10;
int n, k;
int sum;
int fac[maxk];
void Debug() {
#ifdef LOCAL
#endif
}
signed main() {
    n = read(), k = read();
    for(int i = 1; i <= n; i++) {
        int a = read();
        sum = (sum + a) % mod;
    }
    fac[0] = 1;
    for(int i = 1; i <= k; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
    int ans = 0;
    for(int t = 0; t < k; t++) {
        if((k - t) & 1)  // 0
            ans = (ans + 1ll * Pow(1ll * fac[t] * fac[k - 1 - t] % mod, mod - 2, mod) * Pow(t + 1, n - 2, mod) % mod * (n + t) % mod) % mod;
        else
            ans = (ans - 1ll * Pow(1ll * fac[t] * fac[k - 1 - t] % mod, mod - 2, mod) * Pow(t + 1, n - 2, mod) % mod * (n + t) % mod + mod) % mod;
    }
    write(1ll * ans * sum % mod);
    return 0;
}

优秀的 遇见单调队列维护难以撤销的信息,可以考虑过中点重构,均摊 \(O(n)\)


奇怪的 对于奇怪的环相关的特性尝试染色? AT_agc006_f


不会的 发现难以入手记得固定部分条件考虑。


分治的,定值的,背包求体积恰为某值,使用分治背包

选出 \(n,n = 2k\) 个物品,分成两个大小为 \(k\) 的部分,存在方案使得两边体积和之差的绝对值小于体积域 \(m\)。证:滑动窗口。

vector<int> Solve(int n, int L, int R) 函数,递归到 Solve(n / 2, (L - m) / 2, (R + m) / 2) 奇数则单独枚举一位。复杂度 \(O(m^2\log n)\)

DMOPC '21 Contest 8 P5 - Tree Building。

upd2023.10.16:实际上并不需要是恰好。。。


笨蛋的,点权最短路每个点只会被松弛一次


笨蛋的,序列上偶数个数限制可以转化为随机自逆权值求值,无顺序要求可以异或,有顺序要求可以用 \(2\times 2\) 自逆矩阵,奇数也可以试着转偶数。


几何问题可以尝试使用更为简单的表示,如特殊直线。


复杂度可能存在一些不起眼但有用的优化,不要太快放弃,只要可能正确就该尝试算一下复杂度。


stupid,无符号整型一定要先转有符号再比较,特别是参与比较的数可能出现负数的时候。


注意有效状态,有效状态可能远小于全部状态


维护区间加法区间乘积可以尝试多项式,在有神奇特性或模数下项数较小可以使用。


DAG 下对点的问题可以考虑拓扑序小于和大于它的拼起来 P3573 [POI2014] RAJ-Rally。


\(\texttt{01}\) 序列和括号序列可以考虑折线图。映射相关可以考虑反转前/后缀最大值或者取模。


对于排列交换任意两个位置使得序列归位,考虑转图,相关结论:一次操作相当于交换出边,环数最多加一,而归位情况下环数为 \(n\)


没听过的,\(Pr\ddot u fer\)——建立无根树与序列之间的双射,构造方法:选择标号最小的叶子并删掉,记录与其相连的节点,特别的,对于基环树,最后会剩下一个环和一个挂在上面的特殊点,常用于计数。


暴力的,区间取 min/max 区间历史 min/max、区间加减/赋值 区间历史和可以使用矩阵乘法,简单构造即可,注意到有用的点不多,可以只维护有用的点 (初始有值不代表没用!)

例:区间覆盖区间历史和tag
class Val {
public:
    ll a, h, len;
};
class Tag {
public:
    ll a00, a01, a20, a21;
    Tag() = default;
    Tag(ll x, ll y, ll z, ll t) : a00(x), a01(y), a20(z), a21(t) {}
    bool Empty() const {return a00 == 1 && !a01 && !a20 && !a21;}
    void Reset() {a00 = 1, a01 = a20 = a21 = 0;}
};
Tag Mul(const Tag &a, const Tag &b) {
    Tag res;
    res.a00 = a.a00 * b.a00;
    res.a01 = a.a00 * b.a01 + a.a01;
    res.a20 = a.a20 * b.a00 + b.a20;
    res.a21 = a.a20 * b.a01 + a.a21 + b.a21;
    return res;
}
Val Mul(const Val &a, const Tag &b) {
    Val res;
    res.a = a.a * b.a00 + a.len * b.a20;
    res.h = a.a * b.a01 + a.h + a.len * b.a21;
    res.len = a.len;
    return res;
}

tag,存区间和,历史区间和,区间长度:

\[\begin{bmatrix} a & h & len \end{bmatrix} \]

区间覆盖标记:

\[\begin{bmatrix} 0 & 0 & 0 \\ 0 & 1 & 0 \\ val & 0 & 1 \end{bmatrix} \]

区间历史和更新标记:

\[\begin{bmatrix} 1 & 1 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix} \]

有用的只有四个位置:

\[\begin{bmatrix} 1 & 1 & 0 \\ 0 & 1 & 0 \\ 1 & 1 & 1 \end{bmatrix} \]

实际上,需要并行的标记都可以尝试矩阵乘法。


不满足要求的方案数也是前缀,这引诱我们进行容斥。(引用 EI 原话)


正难则反,不仅限于整体,转移时也可以尝试去掉不合法情况。


$\sum_i [x = i] \times i \Leftrightarrow \sum_i [x\geq i] $


天才的,解整数方程可以取模求解。

将实数限制到整数

Tree Weights

\(x_{i + 1} + x_i - 2 x_{lca} = d_i\)

\(x_{i + 1} \equiv d_i - x_i \pmod{2}\)

然后可以求模 \(4\) 的情况,以此类推。


差分约束在字典序上有一定特性。AGC056C


区间问题在去掉包含关系后,通常有更好的性质。


对某一维度的关系要求如果难以处理,可以尝试直接遍历该维度。


prufer 序列好 tm 有用 😠。


计数题整体太难考虑请考虑单个的贡献,谢谢 🐱。


优化 dp 转移可以从分段的角度考虑,常见的类似于 slope trick、维护连续相同段。


\(\prod_{i}a_i \Leftrightarrow\) 每堆中选一个的方案数。


noip1017T4 笨蛋题,均摊一下复杂度 \(O(n^4) \rightarrow O(n^3)\)


树上的 siz 求和可以转化为每个点会被多少次计入 siz。


交换两个不同数对于逆序对个数的影响必定为奇数。


MO 经典套路可知“任意三个点不组成三元环” \(\Longleftrightarrow\) “恰好存在一个点指向
其余两个点。


\(\left\lceil \frac{s_i - s_j}{k} \right\rceil\) 或类似上下取整形式可以拆:\(p_i = \left\lfloor \frac{s_i}{k} \right\rfloor,\ q_i = s_i \bmod k,\ \left\lceil \frac{s_i - s_j}{k} \right\rceil = (p_i - p_j + \left[q_i > q_j\right])\)

三维偏序转二维偏序可以通过提取相同条件,泰tm酷炫了,详见模拟赛题解

断环成链,不关心绝对大小时,可以断成无限长的链!相对大小满足条件即可。


绝对众数可以摩尔投票,也可以二进制位拆分。


线段树分治除了把维护的删除变成撤销,还可以加速 1D 区间转移。

例 noip1031T4

T4

\[f_i = \max_\limits{\begin{array}{c} t_i - R\leq t_j \leq t_i - L\\ c_j \leq b_i\\ |a_i - a_j| \leq h \end{array}} \{f_j + d_j\}\]

考虑 \(t\) 的限制,把这玩意丢到线段树上,后序遍历整个线段树,贡献一定在 \(i\) 之前被计算完,剩下的可以在线段树区间上做,是容易的。

复杂度 \(O(n\log^2 n)\),但我实现很丑,所以是 \(O(n\log n\log V)\)

code
//        No mind to think.
//
//        No will to break.
//
//        No voice to cry suffering.
//
//        Born of God and Void.
//
//        You shall seal the blinding light that plagues their dreams.
//
//        You are the Vessel.
//
//        You are the Hollow Knight.
#ifdef N2
#define _GLIBCXX_DEBUG
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#else 
#define LOG(...)
#endif
#define syncoff ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define NF
#pragma optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 10;
const int mem = 30;
const ll inf = 1e18;
const int rinf = 1e9;
ll f[maxn];
int n, m, g, h, L, R;
class Contest {
public:
    int t, a, b, c, d;
    Contest() = default;
    Contest(int t, int a, int b, int c, int d) : t(t), a(a), b(b), c(c), d(d) {}
}c[maxn];
class SegTree {
public:
    ll tr[maxn * mem];
    int lc[maxn * mem], rc[maxn * mem], cnt, rt;
    void clear() {rt = cnt = 0;}
    void __update(int k) {
        tr[k] = -inf;
        if(lc[k]) tr[k] = max(tr[k], tr[lc[k]]);
        if(rc[k]) tr[k] = max(tr[k], tr[rc[k]]);
    }
    int __new() {
        cnt++;
        tr[cnt] = -inf;
        lc[cnt] = rc[cnt] = 0;
        return cnt;
    }
    void modify(int &k, int l, int r, int addr, ll val) {
        if(!k) k = __new();
        if(l == r) {
            tr[k] = max(tr[k], val);
            return;
        }
        int mid = (l + r) >> 1;
        if(addr <= mid) modify(lc[k], l, mid, addr, val);
        else modify(rc[k], mid + 1, r, addr, val);
        __update(k);
    }
    ll query(int k, int l, int r, int L, int R) {
        if(!k) return -inf;
        if(L <= l && r <= R) return tr[k];
        int mid = (l + r) >> 1;
        ll res = -inf;
        if(L <= mid) res = max(res, query(lc[k], l, mid, L, R));
        if(R > mid) res = max(res, query(rc[k], mid + 1, r, L, R));
        return res;
    }
};
class DpTree {
public:
#define lc (k << 1)
#define rc (k << 1 | 1)
    vector<int> tr[maxn << 2];
    ll tmp[maxn];
    SegTree sgt;
    void insert(int k, int l, int r, int L, int R, int ord) {
        if(L <= l && r <= R) {
            tr[k].emplace_back(ord);
            return;
        }
        int mid = (l + r) >> 1;
        if(L <= mid) insert(lc, l, mid, L, R, ord);
        if(R > mid) insert(rc, mid + 1, r, L, R, ord);
    }
    void calc_init(int n) {for(int i = 1; i <= n; i++) tmp[i] = i;}
    void calc(int k, int l, int r) {
        if(l != r) {
            int mid = (l + r) >> 1;
            calc(lc, l, mid);
            calc(rc, mid + 1, r);
        }
        sort(tr[k].begin(), tr[k].end(), [=](int a, int b) {
            return c[a].b < c[b].b;
        });
        sort(tmp + l, tmp + r + 1, [=](int a, int b) {
            return c[a].c < c[b].c;
        });
        sgt.clear();
        auto it = tr[k].begin();
        for(int i = l; i <= r; i++) {
            while(it != tr[k].end() && c[*it].b < c[tmp[i]].c) {
                int ql = max(c[*it].a - h, 1);
                int qr = min(c[*it].a + h, rinf);
                f[*it] = max(f[*it], sgt.query(sgt.rt, 1, rinf, ql, qr) + c[*it].d);
                it++;
            }
            if(it == tr[k].end()) break;
            sgt.modify(sgt.rt, 1, rinf, c[tmp[i]].a, f[tmp[i]]);
        }
        while(it != tr[k].end()) {
            int ql = max(c[*it].a - h, 1);
            int qr = min(c[*it].a + h, rinf);
            f[*it] = max(f[*it], sgt.query(sgt.rt, 1, rinf, ql, qr) + c[*it].d);
            it++;
        }
        tr[k].clear();
    }
#undef lc 
#undef rc
}dpt;
void Solve() {
    cin >> n >> m >> g >> h >> L >> R;
    for(int i = 1; i <= n; i++) cin >> c[i].t >> c[i].a >> c[i].b >> c[i].c >> c[i].d;
    for(int i = 1; i <= n; i++) f[i] = -inf;
    for(int i = 1; i <= n; i++) {
        if(c[i].t > R) break;
        if(c[i].b >= g)f[i] = c[i].d;
    }
    vector<int> tim;
    for(int i = 1; i <= n; i++) tim.emplace_back(c[i].t);
    tim.resize(unique(tim.begin(), tim.end()) - tim.begin());
    for(int i = 1; i <= n; i++) {
        int l = max(c[i].t - R, 1);
        int r = c[i].t - L;
        if(l > r) continue;
        l = lower_bound(tim.begin(), tim.end(), l) - tim.begin() + 1;
        r = upper_bound(tim.begin(), tim.end(), r) - tim.begin();
        if(l > r) continue;
        dpt.insert(1, 1, n, l, r, i);
    }
    dpt.calc_init(n);
    dpt.calc(1, 1, n);
    ll ans = -inf;
    for(int i = n; i; i--) {
        if(m - c[i].t >= R) break;
        ans = max(ans, f[i]);
    }
    if(ans < -inf / 10) cout << "Retire\n";
    else cout << ans << '\n';
}
int main() {
    #ifndef NF
    freopen("contest.in", "r", stdin);
    freopen("contest.out", "w", stdout);
    #endif
    syncoff;
    int T;
    cin >> T;
    while(T--) Solve();
}

序列上删除一个元素,寻找下一个元素,可以使用并查集。


\(\texttt{DAG}\) 上反图贪心字典序最大求的是正图贪心在 \([1, i-1]\) 的数位置不变的情况下 \(i\) 尽量向前放。


刻画序列上连通块的第一个向前走一步可以用 \(f^k_i = \min\{f^{k - 1}_i + 1, f^{k - 1}_{i + 1} - 1\}\)


splay 合并

将小的 splay 按中序遍历一个个插入到大的 splay 。

可证明复杂度为 \(O(n\log n)\)














nothing

posted @ 2023-09-15 07:42  N2MENT  阅读(74)  评论(0)    收藏  举报