【题解】2020联合省选A卷-Day1
冰火战士
有关卡常
看到\(2\times 10^6\):卡常???那我写树状数组!!
树状数组怎么二分?见这篇CF上的文章。
有关如何二分
用\(a_i\)表示温度为\(i\)的冰战士的
因为实际上求的是
\[\max_i\left\{\min\left\{\sum_{j\le i}a_j,\sum_{j\ge i}b_j\right\}\right\}
\]
而这个形式很难快速求。但是考虑到所有\(a_i,b_i\ge 0\),考虑取最大值时\(\min\)内哪个较小,有两种请况:
- 此时\(\sum_{j\ge i}b_j<\sum_{j\le i}a_j\),且\(\sum_{j\ge i}b_j\)最大,\(i\)最大。
- 此时\(\sum_{j\ge i}b_j\ge \sum_{j\le i}a_j\),且\(\sum_{j\le i}a_j\)最大,\(i\)最大。
由于1、2类似,下面只考虑第一种情况:
令\(sumB=\sum_ib_i\),则可如下变形:
\[\begin{aligned}
\sum_{j\ge i}b_j&<\sum_{j\le i}a_j \\
sumB-\sum_{j<i}b_j&<\sum_{j\le a_j} \\
sumB &< \sum_{j\le i} a_j+b_{j+1}
\end{aligned}
\]
故在\(\{a_i+b_{i+1}\}\)上二分即可以求得最小的\(i\),使得以上等式成立。
此时,需要在使得\(\sum_{j\le i}b_j\)不变的前提下,\(i\)尽量大,再在\(\{b_i\}\)上二分一次即可。
AC(考场)代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define FOR(i,a,b) for (int i = (a); i < (b); ++i)
#define ROF(i,a,b) for (int i = (b)-1; i >= (a); --i)
const int Q = 2e6+10, P = 1<<20;
int q;
int op[Q], t[Q], x[Q], y[Q], k[Q];
int a[Q];
struct BIT{
int t[Q];
void add(int x, int d) {
for (; x < Q; x += x&-x) t[x] += d;
}
int sum(int x) {
int ret = 0;
for (; x; x -= x&-x) ret += t[x];
return ret;
}
int min_g(int x) {
int sum = 0, cur = 0;
for (int k = P; k; k >>= 1) if (cur+k < Q && sum+t[cur+k] <= x) {
sum += t[cur+=k];
}
return cur+1;
}
int max_le(int x) {
return min_g(x)-1;
}
}A, B, AB;
int sumA, sumB;
#define debug printf
signed main() {
freopen("icefire.in", "r", stdin);
freopen("icefire.out", "w", stdout);
scanf("%lld", &q);
int m = 0;
for (int i = 1; i <= q; ++i) {
scanf("%lld", &op[i]);
if (op[i] == 1) {
scanf("%lld%lld%lld", t+i, x+i, y+i);
a[++m] = x[i];
} else {
scanf("%lld", k+i);
}
}
sort(a+1, a+m+1);
m = unique(a+1, a+m+1)-(a+1);
B.add(m+2, 1);
AB.add(m+2, 1);
for (int i = 1; i <= q; ++i) {
if (op[i] == 1) {
x[i] = lower_bound(a+1, a+m+1, x[i])-a;
}
}
//debug("unique: %lld\n", m);
for (int i = 1; i <= q; ++i) {
if (op[i] == 1) {
if (t[i] == 0) A.add(x[i], y[i]), sumA+=y[i];
if (t[i] == 1) B.add(x[i]+1, y[i]), sumB+=y[i];
AB.add(x[i]+(t[i]==1), y[i]);
} else {
if (t[k[i]] == 0) A.add(x[k[i]], -y[k[i]]), sumA-=y[k[i]];
if (t[k[i]] == 1) B.add(x[k[i]]+1, -y[k[i]]), sumB-=y[k[i]];
AB.add(x[k[i]]+(t[k[i]]==1), -y[k[i]]);
}
int ans = 0, power = 0;
int ret1 = AB.min_g(sumB), ret2 = ret1-1; ret1 = B.max_le(B.sum(ret1));
int ans1 = min(A.sum(ret1), sumB-B.sum(ret1));
if (ans1 > power || (ans1 == power && ret1 > ans)) power = ans1, ans = ret1;
int ans2 = min(A.sum(ret2), sumB-B.sum(ret2));
if (ans2 > power || (ans2 == power && ret2 > ans)) power = ans2, ans = ret2;
if (!power) puts("Peace");
else printf("%lld %lld\n", a[ans], power*2);
}
}
组合数问题
定义
下降阶乘幂
\[n^{\underline{k}} = n(n-1)(n-2)\cdots(n-k+1) \qquad n\in R,k \in N\\
\]
特别地,\(n^{\underline{0}}=1\);对\(n\in N, k>n\),\(n^{\underline{k}}=0\)。
(广义)二项式系数
\[{n\choose k} = \frac{n^{\underline k}}{k^{\underline k}} \qquad n\in R, k\in N
\]
特别地,对\(n\in N, k>n\),\({n\choose k}=0\)。
结论
前置性质:对\(i\le k, i\in N\),有\(n^{\underline{k}}=n^{\underline{i}}(n-i)^{\underline{k-i}}\)。
\[{n\choose k}=\frac{n^{\underline{k}}}{k^\underline{k}} = \frac{n^\underline i(n-i)^\underline{k-i}}{k^\underline i (k-i)^\underline{k-i}} = \frac{n^\underline i}{k^\underline i}\cdot{n-i \choose k-i}
\]
预处理
将\(f(x)=\sum_ia_ix^i\)化为下降阶乘幂的形式\(=\sum_ib_ix^{\underline i}\)。
方法:DP(朴素多项式乘法)预处理出对所有\(i\),\(x^{\underline i}=\sum_{j=0}^if_{i,j}x^{j}\)的系数\(f_{i,j}\)。之后用多项式减法。
推式子
\[\begin{aligned}
&\sum_{k=0}^n f(k)x^k{n\choose k} \\
=&\sum_{k=0}^n \sum_{i=0}^m b_i k^{\underline i} x^k\cdot\frac{n^{\underline i}}{k^\underline i}{n-i\choose k-i} \\
=&\sum_{i=0}^m b_i n^{\underline i}x^i \sum_{k=0}^n {n-i\choose k-i}x^{k-i} \\
=&\sum_{i=0}^m b_in^{\underline i}x^i (1+x)^{n-i}
\end{aligned}
\]
由于\(m\le 1000\),可以随便做。