LuoguP8818 [CSP-S 2022] 策略游戏

今年来 S 组摆烂。结果这道题写出了 60 分的好成绩。这是考场上的代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,q,lg[2505];
ll f[16][2505][2505];
ll a[2505],b[2505];
signed main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=2;i<=m;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)scanf("%lld",a+i);
	for(int i=1;i<=m;i++)scanf("%lld",b+i);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			f[0][i][j]=a[i]*b[j];
	for(int k=1;k<=15;k++)
		for(int i=1;i<=n;i++)
			for(int j=1,l=(1<<k);j+l-1<=m;j++){
				f[k][i][j]=min(f[k-1][i][j],
				f[k-1][i][j+(1<<(k-1))]);
			}
	while(q--){
		int l1,r1,l2,r2;
		ll ans=-1e18-1;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		int len=lg[r2-l2+1];
		for(int i=l1;i<=r1;i++){
			ll minn=min(f[len][i][l2],
			f[len][i][r2-(1<<len)+1]);
			ans=max(ans,minn);
		}printf("%lld\n",ans);
	}
	return 0;
}

思路:因为小 L 先,小 Q 肯定只会选 小 L 那行最小的值。 所以小 L 会选最小的值最大的那一行。所以维护 \(N\) 个 ST 表,处理每行最小值,再依次比较最大值。但是会爆空间,时间也过不去。

怎么办呢?


考虑维护 6 个 ST 表,分别记录: A 的最大值、最小值, B 的最大值、最小值, A 的最小非负数、 A 的最大非正数

现在我们在 A 的 ST 表里面选一个, B 的 ST 表里选一个进行组合,其中必有一个是最优解。比较即可。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100505,INF=1e9+1;
int n,m,q,lg[N];
ll mxa[22][N],mna[22][N],mxb[22][N],mnb[22][N],mnp[22][N],mxn[22][N];
//A 的最大值、最小值, B 的最大值,最小值, A 的最小非负数, A 的最大非正数
signed main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=2,len=max(n,m);i<=len;i++)lg[i]=lg[i>>1]+1;
	for(int i=1,a;i<=n;i++){
		scanf("%d",&a);
		mxa[0][i]=mna[0][i]=a;
		if(a<0)mnp[0][i]=2*INF,mxn[0][i]=a;
		else if(a==0)continue;
		else mnp[0][i]=a,mxn[0][i]=-2*INF;
	}
	for(int i=1,b;i<=m;i++){
		scanf("%d",&b);
		mxb[0][i]=mnb[0][i]=b;
	}
	for(int k=1;k<=21;k++)
		for(int i=1,l=(1<<k);i+l-1<=n;i++){
			mxa[k][i]=max(mxa[k-1][i],mxa[k-1][i+(l>>1)]);
			mxn[k][i]=max(mxn[k-1][i],mxn[k-1][i+(l>>1)]);
			mna[k][i]=min(mna[k-1][i],mna[k-1][i+(l>>1)]);
			mnp[k][i]=min(mnp[k-1][i],mnp[k-1][i+(l>>1)]);
		}
	for(int k=1;k<=21;k++)
		for(int i=1,l=(1<<k);i+l-1<=m;i++){
			mxb[k][i]=max(mxb[k-1][i],mxb[k-1][i+(l>>1)]);
			mnb[k][i]=min(mnb[k-1][i],mnb[k-1][i+(l>>1)]);
		}
	while(q--){
		int l1,r1,l2,r2;
		ll ans=-1e18-1;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		int len1=lg[r1-l1+1],len2=lg[r2-l2+1];
		ll mina=min(mna[len1][l1],mna[len1][r1-(1<<len1)+1]);
		ll maxa=max(mxa[len1][l1],mxa[len1][r1-(1<<len1)+1]);
		ll minp=min(mnp[len1][l1],mnp[len1][r1-(1<<len1)+1]);
		ll maxn=max(mxn[len1][l1],mxn[len1][r1-(1<<len1)+1]);
		ll minb=min(mnb[len2][l2],mnb[len2][r2-(1<<len2)+1]);
		ll maxb=max(mxb[len2][l2],mxb[len2][r2-(1<<len2)+1]);
		ans=max(ans,min(maxa*minb,maxa*maxb));
		ans=max(ans,min(mina*minb,mina*maxb));
		if(minp<INF)ans=max(ans,min(minp*minb,minp*maxb));
		if(maxn>-INF)ans=max(ans,min(maxn*minb,maxn*maxb));
		printf("%lld\n",ans);
		
	}
	return 0;
}

特别的整齐~

posted @ 2022-11-12 10:50  robinyqc  阅读(40)  评论(0)    收藏  举报