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;
}
特别的整齐~

浙公网安备 33010602011771号