题解 P8572【[JRKSJ R6] Eltaw】
大家好,我是 CQ-C2024 级蒟蒻 CJH。
题意
题目描述的很清楚了,应该不需要了。
$20$ 分做法
这个数据范围,用普通二维数组是无法存下的,所以这里使用 vector 可变长度数组。
需要区间求和,就要用前缀和优化,每一次询问直接用前缀和求出区间值,再 $1 \sim k$ 枚举选出最大值就行了。
提交记录。
代码:
//the code is from chenjh
#include<bits/stdc++.h>
#define MAXN 500005
using namespace std;
typedef long long LL;
int n,k,q;
vector<LL> a[MAXN];
int main(){
scanf("%d%d%d",&n,&k,&q);
for(int i=1;i<=k;i++){
a[i].resize(n+1);
a[i][0]=0;
for(int j=1;j<=n;j++){
scanf("%lld",&a[i][j]);
a[i][j]+=a[i][j-1];//前缀和。
}
}
while(q--){
int l,r;scanf("%d%d",&l,&r);
// --l,--r;
LL ans=0;
for(int i=1;i<=k;i++)//从 1 ~ k 进行枚举。
ans=max(ans,a[i][r]-a[i][l-1]);
printf("%lld\n",ans);
}
return 0;
}
$50$ 分做法
第二个测试点有一个特殊条件:保证 $l=1$。
所以就可以再开一个数组 $k$ 段中的最大值。
提交记录。
代码:
//the code is from chenjh
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
template <typename T>
inline void read(T &sum){
sum = 0;register short fl = 1;
register int ch=getchar();
for (;ch<'0' || ch>'9';ch=getchar())
if (ch=='-') fl=-1;
for (;ch>='0' && ch<='9';ch=getchar()) sum = (sum <<3 )+(sum<<1)+ (ch^48);
sum*=fl;
}
template <typename T>
inline const void write(T x){
static int sta[35];
register int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) putchar(sta[--top] + 48);
}
inline LL max(LL x,LL y){return x>y?x:y;}
int n,k,q;
vector<LL> a[500005];
LL b[500005];
int main(){
// scanf("%d%d%d",&n,&k,&q);
read(n),read(k),read(q);
for(register int i=1;i<=k;i++){
a[i].resize(n+1);
a[i][0]=0;
for(register int j=1;j<=n;j++){
read(a[i][j]);//scanf("%lld",&a[i][j]);
a[i][j]+=a[i][j-1];
b[j]=max(b[j],a[i][j]);//再开一个数组存储 k 段中 1~j 的最大数。
}
}
while(q--){
int l,r;//scanf("%d%d",&l,&r);
read(l),read(r);
// --l,--r;
if(l==1){write(b[r]);putchar('\n');continue;}//特判 l=1。
LL ans=0;
for(register int i=1;i<=k;i++)
ans=max(ans,a[i][r]-a[i][l-1]);
// printf("%lld\n",ans);
write(ans);putchar('\n');
}
return 0;
}
$100$ 分做法 (Hack 前)
最后一个点还是超时,我用 pair<int,int> 来存储 $l,r$,再用 map 记忆化答案就可以了。
提交记录。
代码:
//the code is from chenjh
#include<cstdio>
#include<vector>
#include<map>
#include<utility>
#define mp make_pair
using namespace std;
typedef long long LL;
namespace IO{//by cyffff
char ibuf[(1<<20)+1],*iS,*iT;
#if ONLINE_JUDGE
#define gh() (iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),(iS==iT?EOF:*iS++):*iS++)
#else
#define gh() getchar()
#endif
#define reg register
inline long long read(){
reg char ch=gh();
reg long long x=0;
reg char t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=gh();
return t?-x:x;
}
}
using IO::read;
template <typename T>
inline const void write(T x){
static int sta[35];
register int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) putchar(sta[--top] + 48);
}
inline LL max(LL x,LL y){return x>y?x:y;}
int n,k,q;
vector<LL> a[500005];
LL b[500005];
map <pair<int,int>,LL> M;//map 存储答案
int main(){
// scanf("%d%d%d",&n,&k,&q);
n=read(),k=read(),q=read();
for(register int i=1;i<=k;i++){
a[i].resize(n+1);
a[i][0]=0;
for(register int j=1;j<=n;j++){
a[i][j]=read();//scanf("%lld",&a[i][j]);
a[i][j]+=a[i][j-1];
b[j]=max(b[j],a[i][j]);
}
}
while(q--){
int l,r;//scanf("%d%d",&l,&r);
l=read(),r=read();
// --l,--r;
if(l==1){write(b[r]);putchar('\n');continue;}
LL ans=M[mp(l,r)];
if(ans){printf("%lld\n",ans);continue;}
for(register int i=1;i<=k;i++)
ans=max(ans,a[i][r]-a[i][l-1]);
// printf("%lld\n",ans);
M[mp(l,r)]=ans;
write(ans);putchar('\n');
}
return 0;
}
$100$ 分做法(Hack 后)
在序列全为 $0$ 时,上面那份代码只有 $50$ 分。
所以这里要多判断一下,再开一个 map 来存储这一段的答案是否计算过。
提交记录。
//the code is from chenjh
#include<cstdio>
#include<vector>
#include<map>
#include<utility>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
namespace IO{//by cyffff
char ibuf[(1<<20)+1],*iS,*iT;
#if ONLINE_JUDGE
#define gh() (iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),(iS==iT?EOF:*iS++):*iS++)
#else
#define gh() getchar()
#endif
#define reg register
inline long long read(){
reg char ch=gh();
reg long long x=0;
reg char t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=gh();
return t?-x:x;
}
}
using IO::read;
template <typename T>
inline const void write(T x){
static int sta[35];
register int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top) putchar(sta[--top] + 48);
}
inline LL max(LL x,LL y){return x>y?x:y;}
int n,k,q;
vector<LL> a[500005];
LL b[500005];
map <PII,LL> M;//第一个 map,存储答案。
map <PII,bool> m;//第二个 map,存储这一段有没有计算过。
int main(){
// scanf("%d%d%d",&n,&k,&q);
n=read(),k=read(),q=read();
for(register int i=1;i<=k;i++){
a[i].resize(n+1);
a[i][0]=0;
for(register int j=1;j<=n;j++){
a[i][j]=read();//scanf("%lld",&a[i][j]);
a[i][j]+=a[i][j-1];
b[j]=max(b[j],a[i][j]);
}
}
while(q--){
int l,r;//scanf("%d%d",&l,&r);
l=read(),r=read();
// --l,--r;
if(l==1){write(b[r]);putchar('\n');continue;}
LL ans=M[mp(l,r)];
if(m[mp(l,r)]){printf("%lld\n",M[mp(l,r)]);continue;}
for(register int i=1;i<=k;i++)
ans=max(ans,a[i][r]-a[i][l-1]);
// printf("%lld\n",ans);
M[mp(l,r)]=ans,m[mp(l,r)]=1;//标记此段已计算并写出答案。
write(ans);putchar('\n');
}
return 0;
}
谢谢大家!

浙公网安备 33010602011771号