[JZOJ5187]【NOIP2017提高组模拟6.30】tty's maze

Descrption

给出一个N*M的矩阵,每个格子有正整数权值,每一列的格子权值都是一样的,上下左右走格子,第一次走到这个格子可以获得之,总共可以走K个格子(走过的也算)。第一行可以瞬移到最后一行

求最大获得权值
N,M<=1e7,权值<=1e7,K<=nm

Solution

第一行可以一步走到最后一行,这意味着,从左向右走,无论我们从哪一个位置进入这一列,都可以不走重复路的获得完这一列的权值,因为一进入就可以一直向上,到第一行后瞬移到最后一行,从进入的格子的下面一格出来。

那么有推论,一定不会向左走,因为不妨在向右走之前就走完左边要走的,一定更节约步数。

继续。
对于每一列,要么根本没到这里,要么只走一个(就是经过它而不去走这一列其它的格子),要么走完这一列。

那么假设我们向右走了P列,在前P列走完的列数是确定的,完全可以贪心的想直接走最大的那些列。

随便用个什么数据结构维护一下。

也可以用一个链表。先把所有列权值排序,倒过来用单调栈求出每一列在它前面比它大,和它最接近的列,链表直接插入就可以。
不要用STL(set、priority_queue等),很容易T

Code

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 1000005
#define LL long long
using namespace std;
int n,m,a[N],nt[N],fs,d[N],c[N],l[N];
bool bz[N];
void read(int &x)
{
    x=0;char c;bool fg=0;
    while((unsigned)((c=getchar())-'0')>9) {if(c=='-')fg=1;if(c==-1) return;}
    do{x=(x<<3)+(x<<1)+(c-'0');}while((unsigned)((c=getchar())-'0')<=9);
    if(fg) x=-x;
}
LL ans,num;
bool cmp(int x,int y)
{
    return (a[x]<a[y]||(a[x]==a[y]&&x<y));
}
void push(int k)
{
    if(bz[l[k]]||l[k]==0) nt[k]=fs,fs=k;
    else nt[k]=nt[l[k]],nt[l[k]]=k;
}
void pop()
{
    fs=nt[fs];
}
int main()
{
    cin>>n>>m>>num;
    fo(i,1,m) read(a[i]),c[i]=i;
    sort(c+1,c+m+1,cmp);
    int top=0;
    fod(i,m,1)
    {
        while(top>0&&d[top]>c[i]) l[d[top--]]=c[i];
        d[++top]=c[i];
    }
    fs=0;
    LL ans=0,s=0,s1=0;
    int w=0;
    fo(i,1,m)
    {
        if(num<i) break;
        push(i);
        s+=a[i],s1+=a[i];
        LL v=((n!=1)?(LL)(num-i)/(n-1):num);
        LL v1=num-i-v*(n-1);
        v1=(v1>n-1)?n-1:v1;
        v++;
        w++;
        if(v1<0)w--,s-=a[fs],bz[fs]=1,pop();
        while(w>v) w--,s-=a[fs],bz[fs]=1,pop();
        LL sn=s*(LL)(n-1)+s1-((w==v)?(LL)(n-1-v1)*a[fs]:0);
        ans=(ans<sn)?sn:ans;
    }
    printf("%lld\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值