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:
容易想到一个柿子
后面的部分拆出来
带入斯特林数通项公式
后面的不太好做,但前面的形式挺不错的
\(s\) 和 \(s - 1\) 差 \(1\) 试着拼一下把 \(s\) 换出来
组合数不好算,但是幂好算,发现两个式子都是二项式定理的结构,配个 \(1\) 凑出来
剩下的都很好算,幂次为负数时特判一下
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,存区间和,历史区间和,区间长度:
区间覆盖标记:
区间历史和更新标记:
有用的只有四个位置:
实际上,需要并行的标记都可以尝试矩阵乘法。
不满足要求的方案数也是前缀,这引诱我们进行容斥。(引用 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
考虑 \(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