首页 > 其他分享 >P8182 「EZEC-11」雪的魔法 / NOIP 模拟赛 20230706 D 思考--zhengjun

P8182 「EZEC-11」雪的魔法 / NOIP 模拟赛 20230706 D 思考--zhengjun

时间:2023-07-06 21:56:57浏览次数:45  
标签:11 20230706 NOIP int max -- ques ans id

引用:这是一道非常棒的思维题,可以说没有用到任何高深的知识点,却极大地考验了做题人的思维能力和创造性。

本题分为两步。

  • 根据线性规划对偶或贪心,转化题意。

  • 对 \(m\) 根号分治,然后分别进行分治。

\(m\le \sqrt{n}\)分治比较好想,\(m>\sqrt{n}\) 的根号分治比较难想。

这两种分治的细节都很多,调了一整天

原题还卡常,无语了

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e5+10;
int n,m,q,qt,B;
ll a[N*2],b[N],c[N],ans[N],sum[N];
struct ques{
	int l,r,id;
}o[N];
namespace ST{
	const int K=__lg(N)+2;
	ll f[K][N];
	void build(){
		for(int i=1;i<=n;i++)f[0][i]=a[i];
		for(int i=1;(1<<i)<=n;i++)
			for(int j=1;j+(1<<i)-1<=n;j++)
				f[i][j]=max(f[i-1][j],f[i-1][j+(1<<i-1)]);
	}
	ll query(int l,int r){
		int k=__lg(r-l+1);
		return max(f[k][l],f[k][r-(1<<k)+1]);
	}
}
void reduce(){
	qt=q,q=0;
	for(int i=1;i<=qt;i++){
		if(o[i].r-o[i].l+1>m)o[++q]=o[i];
		else if(o[i].l<=o[i].r)
			ans[i]=max(ans[i],ST::query(o[i].l,o[i].r));
	}
}
namespace Solve1{
	ll f[N],g[N];
	void solve(int l,int r,vector<ques>o){
		if(o.empty()||r-l+1<=m)return;
		vector<ques>L,R,T;
		int mid=(l+r)>>1;
		for(ques x:o){
			if(x.r<=mid)L.push_back(x);
			else if(mid<x.l)R.push_back(x);
			else T.push_back(x);
		}
		solve(l,mid,L),solve(mid+1,r,R);
		if(T.empty())return;
//		for(int i=73;i<=93;i++)printf("%lld%c",a[i],"\n "[i<93]);
		for(int d=0;d<=m;d++){
			int L=mid-d+1,R=L+m-2;
			L=max(L,l),R=min(R,r);
			for(int i=L;i<=mid;i++)f[i]=0;
			for(int i=R;i>mid;i--)g[i]=0;
			f[L]=g[R]=0;
			for(int i=L-1;i>=l;i--){
				f[i]=max(f[i+1],(i+m<L?f[i+m]:0)+a[i]);
			}
			for(int i=R+1;i<=r;i++){
				g[i]=max(g[i-1],(i-m>R?g[i-m]:0)+a[i]);
			}
			for(ques x:T)ans[x.id]=max(ans[x.id],f[x.l]+g[x.r]);
		}
	}
	void solve(){
		solve(1,n,{o+1,o+1+q});
	}
}
namespace Solve2{
	#define id(x,y) ((y)*m+(x))
	const int S=sqrt(N)+5,M=N*2;
	int h,b[M];
	struct ques{
		int a,b,x,y,id;
	};
	ll sum[S],c[M],f[M],g[M];
	int k,gap;
	void solve(int l,int r,vector<ques>o){
		if(o.empty())return;
		if(l==r){
			for(int i=0;i<h;i++)sum[i]=(i?sum[i-1]:0)+a[id(l,i)];
			for(ques x:o)ans[x.id]=max(ans[x.id],sum[x.x]-(x.a?sum[x.a-1]:0));
			return;
		}
		int mid=(l+r)>>1;
		vector<ques>L,R;
		for(ques x:o)if(x.b<=x.y){
			if(x.b<=mid&&x.y<=mid)L.push_back(x);
			else if(mid<x.b&&mid<x.y)R.push_back(x);
		}
		solve(l,mid,L),solve(mid+1,r,R);
		gap=r-l+1,k=0;
		for(int i=0;i<h;i++)for(int j=l;j<=r;j++){
			b[id(j,i)]=++k,c[k]=a[id(j,i)];
		}
		for(int l=1-gap,r=0,i=0;i<=h+1;l+=gap,r+=gap,i++){
			for(int j=min(l-1,k);j>=1;j--)f[j]=max(f[j+1],(j+gap<=k?f[j+gap]:0)+c[j]);
			for(int j=max(r+1,1);j<=k;j++)g[j]=max(g[j-1],(j>gap?g[j-gap]:0)+c[j]);
			for(ques x:o)if(b[id(x.b,x.a)]<=r&&b[id(x.y,x.x)]>=l){
				ans[x.id]=max(ans[x.id],f[b[id(x.b,x.a)]]+g[b[id(x.y,x.x)]]);
			}
			for(int j=min(l-1,k);j>=1;j--)f[j]=0;
			for(int j=max(r+1,1);j<=k;j++)g[j]=0;
		}
		for(int r=(gap+1)/2,l=r-gap+1,i=0;i<=h;l+=gap,r+=gap,i++){
			for(int j=min(l-1,k);j>=1;j--)f[j]=max(f[j+1],(j+gap<=k?f[j+gap]:0)+c[j]);
			for(int j=max(r+1,1);j<=k;j++)g[j]=max(g[j-1],(j>gap?g[j-gap]:0)+c[j]);
			for(ques x:o)if(b[id(x.b,x.a)]<=r&&b[id(x.y,x.x)]>=l){
				ans[x.id]=max(ans[x.id],f[b[id(x.b,x.a)]]+g[b[id(x.y,x.x)]]);
			}
			for(int j=min(l-1,k);j>=1;j--)f[j]=0;
			for(int j=max(r+1,1);j<=k;j++)g[j]=0;
		}
//		cerr<<l<<' '<<r<<' '<<ans[1]<<endl;
	}
	void solve(){
		h=(n-1)/m+1;
		vector<ques>o(q);
		for(int i=0;i<q;i++){
			o[i].a=::o[i+1].l/m;
			o[i].b=::o[i+1].l%m;
			o[i].x=::o[i+1].r/m;
			o[i].y=::o[i+1].r%m;
			o[i].id=::o[i+1].id;
		}
		solve(0,m-1,o);
	}
}
int main(){
	freopen("snow.in","r",stdin);
	freopen("snow.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q),B=sqrt(n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<n;i++)if(a[i]>a[i+1]){
		b[i]=a[i]-a[i+1];
		c[max(i-m+1,1)]-=b[i],c[i+1]+=b[i];
	}
	for(int i=1;i<=n;i++)b[i]+=b[i-1],c[i]+=c[i-1];
	for(int i=1;i<=q;i++){
		scanf("%d%d",&o[i].l,&o[i].r),o[i].id=i;
//		for(int j=o[i].l;j<=o[i].r;j++)printf("%lld%c",a[j],"\n "[j<o[i].r]);
		sum[i]=b[o[i].r-1]-b[o[i].l-1]+a[o[i].r];
		o[i].r-=m;
	}
	for(int i=1;i<=n;i++)a[i]=max(a[i]+c[i],0ll);
	ST::build();
	reduce();
	if(m<=B)Solve1::solve();
	else Solve2::solve();
	for(int i=1;i<=qt;i++)printf("%lld\n",ans[i]+sum[i]);
	return 0;
}

标签:11,20230706,NOIP,int,max,--,ques,ans,id
From: https://www.cnblogs.com/A-zjzj/p/17533428.html

相关文章

  • 119子类依旧使用父类的属性和方法
    classPhone:IMEI=2020001producer="apple"defcall_by_4g(self):print("4g通话")classMyPhone2(Phone):IMEI=2023001producer="banana"defcall_by_4g(self):old_return_value=super......
  • QOJ 5500. Bars / NOIP 模拟赛 20230706 B 进阶版--zhengjun
    本题转化为梯形面积就已经不是很好想了(赛时切掉,开心!)进阶为静态区间查询。使用不删除莫队+凸包合并凸包合并就是把散块和整块的凸包合并注意这里两个凸包的横坐标值域是无交的于是可以使用二分套二分解决此问题代码咕着,感觉非常难写......
  • 复习ES(6-11)语法之ES6下篇
    目录异步操作前置知识PromiseGenerator原理用法异步状态管理Iterator原生具备Iterator接口的数据结构Generator遍历不可迭代对象模块化规范异步操作前置知识JS是单线程的单线程即一个时间只能处理一个任务。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM......
  • CodeForces 1142E Pink Floyd
    洛谷传送门CF传送门感觉很神奇啊,想了挺久的。如果没有粉色边是容易的。竞赛图中,强连通分量缩点后,拓扑序较小的点向每一个拓扑序比它大的点连边。利用这个性质,我们维护一个答案集合\(S\),当\(|S|\ge2\)时,每次随意取出两个点\(u,v\inS\)。如果边的方向是\(u\tov\)......
  • 「NOIP 模拟赛 20230706」轨道飞跃
    summarizationsolution考虑倒着走,那么从\(u\)走到\(v\)条件就变为\(r_v\)在\(u\)所在的区间内,于是我们预处理出右端点在这段区间内的轨道的左端点的最小值(可以用ST表),然后从\(t\)跳回\(s\)。不难发下,往回跳的过程可以用倍增优化(具体见代码),最终复杂度\(\mathcal{O......
  • 20230706巴蜀暑期集训测试总结
    T1我是个大聪明!一眼矩乘。构造转移矩阵构造了3.5h!最开始以为只有\(15\times15\),直接手打。写到一半发现不一定四种颜色都有,是\(52\times52\)的,这时候狗被脑子吃了,还想手打,于是就打到了3h。差不多打了一大半,脑子终于把狗还回来了,意识到就算打完也不可能调得出来,就开始另辟蹊径,......
  • ubuntu系统安装jdk报错debianutils : Breaks: x11-common (< 1:7.7+23~) but 1:7.7+19
    问题:Ubuntu系统执行aptinstallopenjdk-8-jdk 安装jdk8报错root@2b6d781ebc36:/#aptinstallopenjdk-8-jdkReadingpackagelists...DoneBuildingdependencytree...DoneReadingstateinformation...DoneSomepackagescouldnotbeinstalled.Thismaymeanthatyo......
  • C++11:总结
     autodecltypeRvaluereferencesandmovesemanticsLambdaexpressionsnullptrstatic_assertRangebasedforloopTrailingreturntypeinfunctionsfinalmethodkeywordoverridemethodkeywordStronglytypedenumsForwarddeclaredenumsexterntemplates......
  • 「NOIP 模拟赛 20230705」序列删数问题
    summarizationsolution首先发现,范围小的工具在删除某一数字时将更大数字包括进来的可能性越小,可以删除的数更多,所以在删除某一数字时应该尽可能选择范围较大的工具。接下来我们考虑可删数(要删除的数)删除的顺序:考虑要删掉每个数所允许的最大的工具的区间长度。现在假设有两个......
  • Day02-11 用户交互Scanner
    Scanner对象之前我们学的基本语法中我们并没有实现程序和人的交互,但是java给我们提供了这样一个工具类,我们可以获取用户的输入。java.util.Scanner是java5的新特征,我们可以通过Scanner类来获取用户的输入。基本语法:Scanners=newScanner(System.in);通过Scanner类......