题解2020联合省选A卷-Day1
Posted top_secret的小尛博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解2020联合省选A卷-Day1相关的知识,希望对你有一定的参考价值。
冰火战士
有关卡常
看到\\(2\\times 10^6\\):卡常???那我写树状数组!!
树状数组怎么二分?见这篇CF上的文章。
有关如何二分
用\\(a_i\\)表示温度为\\(i\\)的冰战士的
因为实际上求的是
而这个形式很难快速求。但是考虑到所有\\(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\\),则可如下变形:
故在\\(\\{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{0}}=1\\);对\\(n\\in N, k>n\\),\\(n^{\\underline{k}}=0\\)。
(广义)二项式系数
特别地,对\\(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}}\\)。
预处理
将\\(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}\\)。之后用多项式减法。
推式子
由于\\(m\\le 1000\\),可以随便做。
以上是关于题解2020联合省选A卷-Day1的主要内容,如果未能解决你的问题,请参考以下文章
luoguP6623 [省选联考 2020 A 卷] 树(trie树)