D
对顶堆模板
题意
每次增加两个元素,问中位数,保证集合大小一直是奇数
分析
动态求中位数,直接对顶堆。pypypy的话sortedlist也可以,可惜cppcppcpp没有这种方便的库
c
struct Set {
const int kInf = 1e9 + 2077;
std::multiset<int> less, greater;
void init() {
less.clear(), greater.clear();
less.insert(-kInf), greater.insert(kInf);
}
void adjust() {
while (less.size() > greater.size() + 1) {
std::multiset<int>::iterator it = (--less.end());
greater.insert(*it);
less.erase(it);
}
while (greater.size() > less.size()) {
std::multiset<int>::iterator it = greater.begin();
less.insert(*it);
greater.erase(it);
}
}
void add(int val_) {
if (val_ <= *greater.begin())
less.insert(val_);
else
greater.insert(val_);
adjust();
}
void del(int val_) {
std::multiset<int>::iterator it = less.lower_bound(val_);
if (it != less.end()) {
less.erase(it);
} else {
it = greater.lower_bound(val_);
greater.erase(it);
}
adjust();
}
int get_middle() {
return *less.rbegin();
}
};
void solve() {
int x, q;
cin >> x >> q;
Set s;
s.init();
s.add(x);
rep(i, 1, q) {
int a, b;
cin >> a >> b;
s.add(a);
s.add(b);
cout << s.get_middle() << '\n';
}
}
E
组合数学 隔板法
题意
1,2,31,2,31,2,3分别x1,x2,x3x_1,x_2,x_3x1,x2,x3个,组成一个序列,要求相邻元素差的绝对值不超过111。问有多少个不同序列?
分析
注意到不满足这个要求的只有1,31,31,3直接相邻,所以可以把222当成隔板,吧1,31,31,3隔开。有x2x_2x2个222,则划分出x2+1x_2+1x2+1个区域,每个区域里要么空,要么全是111,要么全是333
那么枚举x1x_1x1有iii段,从x2+1x_2+1x2+1个位置里选iii段给111,方案数C(x1+1,i)C(x_1+1,i)C(x1+1,i),把x1x_1x1个111放进iii个位置里,不妨设不允许空位,这是经典球盒问题,方案数C(x1−1,i−1)C(x_1-1,i-1)C(x1−1,i−1),剩下的x2+1−ix_2+1-ix2+1−i位置拿来放x3x_3x3个333,允许空盒,方案数C(x2+1−i+x3−1,x3)C(x_2+1-i+x_3-1,x_3)C(x2+1−i+x3−1,x3)
实现
c
void solve() {
int x, y, z;
cin >> x >> y >> z;
int ans = 0;
int box = y + 1;
rep(i, 1, x) {
ans += C(y + 1, i) * C(x - 1, i - 1) % M2 * C(box - i + z - 1, z) % M2;
ans %= M2;
}
cout << ans;
}
F
AC 自动机 矩阵快速幂优化DPDPDP
题意
和给101010个串,长度不超过101010,问长度为1e91e91e9的,不含这些串作为子串的串个数?
分析
模式串不能出现,问合法串数,这可以KMPKMPKMP思想,维护模式串匹配到哪了,如果完成了一个完整的模式串匹配,那么从这个状态开始,接下来到的状态,都标记为非法。
这样我们构建了一个自动机,上面一些节点是非法的。把非法节点删掉,得到的子图是一个只接受合法串的自动机。求走nnn步的方案数,在这个自动机上从初态开始,转移nnn次,每个点保存到达这个状态的方案数,然后对所有状态方案数求和。
这里有多个模式串的话,KMPKMPKMP拓展到ACACAC自动机即可。先ACACAC自动机建出来,然后把这个自动机对应的图写成一个邻接矩阵的形式,求n=1e9n=1e9n=1e9步的结果,对这个矩阵做矩阵快速幂即可。
c
struct Aho_Corasick_Automaton {
queue<int> q;
int c[N][26], val[N], fail[N], cnt;
void init() {
memset(c, 0, sizeof(c));
memset(val, 0, sizeof(val));
memset(fail, 0, sizeof(fail));
cnt = 0;
}
void ins(string &s) {
int len = s.size();
int now = 0;
for (int i = 0; i < len; i++) {
int v = s[i] - 'a';
if (!c[now][v]) c[now][v] = ++cnt;
now = c[now][v];
}
val[now]++;
}
void build() {
for (int i = 0; i < 26; i++) if (c[0][i]) fail[c[0][i]] = 0, q.push(c[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop();
val[u] |= val[fail[u]];
for (int i = 0; i < 26; i++)
if (c[u][i]) fail[c[u][i]] = c[fail[u]][i], q.push(c[u][i]);
else c[u][i] = c[fail[u]][i];
}
}
} AC;
typedef vector<vector<long long>> Matrix;
// 矩阵乘法
Matrix multiply(const Matrix &A, const Matrix &B, long long MOD) {
int n = A.size();
int m = B[0].size();
int k = B.size();
Matrix C(n, vector<long long>(m, 0));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
for (int l = 0; l < k; ++l) {
C[i][j] = (C[i][j] + A[i][l] * B[l][j] % MOD) % MOD;
}
}
}
return C;
}
// 矩阵快速幂
Matrix power(Matrix A, long long p, long long MOD) {
int n = A.size();
Matrix result(n, vector<long long>(n, 0));
// 初始化结果矩阵为单位矩阵
for (int i = 0; i < n; ++i) {
result[i][i] = 1;
}
while (p) {
if (p % 2 == 1) {
result = multiply(result, A, MOD);
}
A = multiply(A, A, MOD);
p /= 2;
}
return result;
}
void solve() {
int n, k;
cin >> n >> k;
AC.init();
rep(i, 1, k) {
string s;
cin >> s;
AC.ins(s);
}
AC.build();
int tot = AC.cnt + 1;
Matrix f(tot, vi(tot));
rep(i, 0, tot - 1) {
if (AC.val[i])continue;
rep(j, 0, 25) {
int nxt = AC.c[i][j];
if (!AC.val[nxt]) {
f[i][nxt]++;
}
}
}
f = power(f, n, M2);
int ans = 0;
rep(i, 0, tot - 1) {
if (!AC.val[i]) {
ans = (ans + f[0][i]) % M2;
}
}
cout << ans;
}