码迷,mamicode.com
首页 > 其他好文 > 详细

联合省选2020 A卷 题解

时间:2021-06-18 20:15:31      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:直接   des   https   依次   离散   uniq   离散化   集合   puts   

D1T1 冰火战士

Description

有两个元素集合 \(S,T\),每个元素都有权值 \(c,w\)\(q\) 次插入或删除一个元素,询问:

\[\max_{t}(2\min(\sum_{i\in S}[c_i\le t]w_i,\sum_{i\in T}[c_i\ge t]w_i)) \]

并求出达到最大值的 \(t\),若有多个 \(t\) ,取其中最大的。

\(q\le 2\times 10^6,c_i\le 2\times 10^9\)

Solution

首先最终的 \(t\) 一定会在某一个 \(c_i\) 处取到,因此可以先将 \(c_i\) 离散化。

由于最终求的是两坨东西的 \(\min\)\(\max\),(不妨设分别为 \(a_t,b_t\)),又注意到 \(a_t\) 是不降的函数,\(b_t\) 是不增的函数,因此答案一定在二者交界处附近取到,考虑先找到交界点,也就是 \(a_t-b_t\) 这一不降函数的零点。

求不降函数的零点,容易想到直接用线段树维护 \(a_t-b_t\),然后在线段树上二分,这样做是 \(\mathcal O(n\log n)\) 的,但常数较大,可能会被卡。

事实上,我们也可以用树状数组维护,具体而言,用两棵树状数组分别维护 \(a_t\)\(b_t\)。找交界点时,假设现在我们正在 \(pos\) 位置(初始为 \(0\)),目前的 \(a_{pos}-b_{pos}\le 0\),然后考虑向后跳 \(2\) 的次幂,按 \(d\) 从大到小依次考虑 \(now=pos+2^d\) 是否依然满足 \(a_{now}-b_{now}\le 0\) ,如果是,直接跳到 \(now\) 的位置,否则就不跳,将步幅减小。再判断新点是否符合时,新增的部分就是树状数组上点 \(now\) 维护的信息,因此可以 \(\mathcal O(1)\) 进行判断。

至此我们 \(\mathcal O(n\log n)\) 的找到了最大的使得 \(a_t\le b_t\)\(t\)\(t+1\) 就是最小的 \(a_t>b_t\)\(t\),显然答案一定在它们中产生。注意当 \(t+1\) 为最终答案时,它不一定是所有这样的 \(t\) 中最大的,我们可以通过再一次二分来找到最终答案。

最终复杂度为小常数 \(\mathcal O(n\log n)\)

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int q,d[N],tot,ct[2];
struct node{
	int t,x,y;
}a[N]; 
struct BIT{
	int c[N];
	inline int lowbit(int x){return x&(-x);}
	inline void update(int x,int y){
		for(;x<=tot;x+=lowbit(x)) c[x]+=y;
	}
	inline int query(int x){
		int ans=0;
		for(;x;x-=lowbit(x)) ans+=c[x];
		return ans;
	}
}T[2];
int dt;
int main(){
	scanf("%d",&q);
	for(int i=1,op,k;i<=q;++i){
		scanf("%d",&op);
		if(op==1) scanf("%d%d%d",&a[i].t,&a[i].x,&a[i].y);
		else{
			scanf("%d",&k);
			a[i]=a[k];a[i].y=-a[i].y;
		}
		d[i]=a[i].x;
	}
	sort(d+1,d+q+1);
	tot=unique(d+1,d+q+1)-d-1;
	for(int i=1;i<=q;++i){
		a[i].x=lower_bound(d+1,d+tot+1,a[i].x)-d;
		int tp=a[i].t;
		if(a[i].y>0) ct[tp]++;
		else ct[tp]--;
		if(!tp) T[0].update(a[i].x,a[i].y);
		else T[1].update(a[i].x+1,-a[i].y),dt+=a[i].y;
		if(!ct[0]||!ct[1]){puts("Peace");continue;}
		int now=0,ret=-dt;
		for(int i=20;i>=0;--i){
			if(now+(1<<i)>tot) continue;
			int x=now+(1<<i);
			if(T[0].c[x]-T[1].c[x]+ret<=0) now=x,ret+=T[0].c[x]-T[1].c[x];
		}
		ret=min(T[0].query(now),T[1].query(now)+dt);
		int tmp=min(T[0].query(now+1),T[1].query(now+1)+dt);
		if(now<tot&&tmp>=ret){
			int lim=T[1].query(now+1);
			ret=0;now=0;
			for(int i=20;i>=0;--i){
				if(now+(1<<i)>tot) continue;
				int x=now+(1<<i);
				if(ret+T[1].c[x]>=lim) ret+=T[1].c[x],now=x;
			}
			ret=tmp;
		}
		if(!ret){puts("Peace");continue;}
		printf("%d %d\n",d[now],ret<<1);
	}
	return 0;
}

D1T2 组合数问题

Description

请求出:

\[\sum_{k=0}^{n}f(k)x^k\binom nk\pmod p \]

其中 \(f(k)\) 是关于给定的一个 \(m\) 次多项式 \(f(k)=\sum_{i=0}^{m}a_ik^i\)

\(m\le 1000,n,x,p\le 10^9\)

Soltion

首先将多项式展开:

\[=\sum_{k=0}^{n}\sum_{i=0}^{m}a_ik^ix^k\binom nk\=\sum_{i=0}^{m}a_i\sum_{k=0}^{n}k^ix^k\binom nk \]

注意到 \(x^k\dbinom nk\) 类似二项式定理的形式,而前面这个 \(k^i\) 怎么看怎么不对劲,于是套路的将它转化为下降幂:

\[=\sum_{i=0}^{m}a_i\sum_{k=0}^{n}\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}k^{\underline{j}} x^k\binom nk\=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}\sum_{k=0}^{n}k^{\underline{j}} x^k\binom nk\=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}\sum_{k=0}^{n}\binom{k}{j}j! x^k\binom nk\\]

这是三项式系数,可以转化为

\[=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}j!\sum_{k=0}^{n}\binom{n}{j}\binom{n-j}{k-j} x^k\=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}j!\binom nj\sum_{k=0}^{n-j}\binom{n-j}{k} x^kx^j\\]

终于舒服了,二项式定理得到:

\[=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}\ \left\{\begin{matrix}i\\j\end{matrix}\right\}j!\binom njx^j(x+1)^{n-j} \]

直接递推处理第二类斯特林数,即可做到 \(\mathcal O(m^2)\)

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;
struct FastMod{
	typedef unsigned long long ULL;
	typedef __uint128_t LLL;
	ULL b,m;
	void init(ULL b){this->b=b,m=ULL((LLL(1)<<64)/b);}
	ULL operator()(ULL a)const{
		ULL q=(ULL)((LLL(m)*a)>>64);
		ULL r=a-q*b;
		return r>=b?r-b:r;
	}
}mod;
inline ll operator %(ll x,const FastMod &mod){return mod(x);}
int n,x,md,m,a[N],str[N][N],base[N],low[N];
inline int ksm(int x,int y){
	int ret=1;
	for(;y;y>>=1,x=1ll*x*x%mod) if(y&1) ret=1ll*ret*x%mod;
	return ret; 
}
inline void init(){
	for(int i=str[0][0]=1;i<=m;++i){
		for(int j=1;j<=m;++j)
			str[i][j]=(str[i-1][j-1]+1ll*j*str[i-1][j])%mod;
	}
	low[0]=1;
	for(int i=1;i<=m;++i) low[i]=1ll*low[i-1]*(n-i+1)%mod;
}
int main(){
	scanf("%d%d%d%d",&n,&x,&md,&m);
	mod.init(md);
	init();
	int ans=0;
	for(int i=0;i<=m;++i){
		scanf("%d",&a[i]);
		int ret=0,pw1=1;
		for(int j=0;j<=i;++j,pw1=1ll*pw1*x%mod)
			ret=(ret+1ll*str[i][j]*low[j]%mod*pw1%mod*ksm(x+1,n-j))%mod;
		ans=(ans+1ll*ret*a[i])%mod;
	}
	printf("%d\n",ans);
	return 0;
}

D1T3 魔法商店

这是一道神仙论文题,我在之前的博客保序回归问题中已进行了详细的讲解。

联合省选2020 A卷 题解

标签:直接   des   https   依次   离散   uniq   离散化   集合   puts   

原文地址:https://www.cnblogs.com/tqxboomzero/p/14900395.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!