其他分享
首页 > 其他分享> > 【题解】2020联合省选A卷-Day1

【题解】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\)内哪个较小,有两种请况:

  1. 此时\(\sum_{j\ge i}b_j<\sum_{j\le i}a_j\),且\(\sum_{j\ge i}b_j\)最大,\(i\)最大。
  2. 此时\(\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\),可以随便做。

标签:le,power,省选,题解,sum,ge,2020,choose,underline
来源: https://www.cnblogs.com/topsecret/p/2020-shengxuan.html