题解 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;
}

谢谢大家!

posted @ 2022-10-05 21:53  Chen_Jinhui  阅读(15)  评论(0)    收藏  举报  来源