您的位置:首页 > 其它

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

2017-07-01 15:38 363 查看

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
,nt
,fs,d
,c
,l
;
bool bz
;
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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: