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

来源:互联网 发布:澳门网络博客有限公司 编辑:程序博客网 时间:2024/06/05 17:02

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 longusing 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);}
阅读全文
0 0
原创粉丝点击