ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1070 [NOIP2009 普及组] 道路游戏

2021-07-31 01:01:00  阅读:169  来源: 互联网

标签:普及 int max NOIP2009 getchar 队列 while include P1070


道路游戏

给定一个长度为 \(n\) 的环,每条边每个时刻都有对应的价值,经过即得到。

每个时刻如果没有在运动,就可以任意选择起点和持续运动时间,每次运动将移动一条边的长度。

对于选择的起点 \(i\) 需要减去 \(a_i\) 的价值,\(a_i\) 不随时间变化改变。

求最终价值的最大值,有可能为负。

\(f(i)\)​ 表示第 \(i\)​ 个时刻的 \(\max\)​​。\(g(i,j)\)​​ 位置 \(i\)​ 时间 \(j\)​ 斜线上的前缀和。

\(f(i)=\max\limits_{0<j<n,1\leq k\leq p}\{f(i-k)+g(j-1,i)-g(j-k-1,i-k)-a(j-k)\}\)​

这样可以做到 \(O(n^3)\),需要追求优化。​​

设 \(h(i,j)=f(i)-g(j-1,i)-a(j)\)

\(f(i)=\max\limits_{0<j<n,1\leq k\leq p}\{h(i-k,j-k)+g(j-1,i)\}\)

相当于是斜线上的单调队列,至于队列编号的钦定...,不妨定为 \((i-j+1)\mod n\)​。

这样钦定的原因是,第一行的队列编号就是 \(0\sim n-1\),比较优美。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 1010;
const int INF = 1e9;
int n, m, p;
int f[N], a[N], g[N][N];

int read(){
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

#define MP make_pair
#define V first
#define P second
typedef pair<int, int> PII;

struct Queue{
	int l, r; PII q[N];
	void Init(){l = 1, r = 0;}
	int Front(){return q[l].V;}
	void Push(int i, int val){
		while(l <= r && q[r].V <= val) r --;
		q[++ r] = MP(val, i);
	}
	void Pop(int limit){
		while(l <= r && q[l].P < limit) l ++;
	}
} Q[N];

int Get(int i, int j){return ((i - j) + 2 * n) % n;}

int main(){
	n = read(), m = read(), p = read();
	for(int i = 0; i < n; i ++)
		for(int j = 1; j <= m; j ++) g[i][j] = read();
	for(int i = 0; i < n; i ++) a[i] = read();

	for(int j = 2; j <= m; j ++)
		for(int i = 0; i < n; i ++)
			g[i][j] += g[Get(i, 1)][j - 1];
	for(int i = 0; i < n; i ++){
		int k = (i == n - 1) ? 0 : i + 1;
		Q[k].Init();
		Q[k].Push(0, - a[i]);
	}

	for(int i = 1; i <= m; i ++) f[i] = - INF;
	for(int i = 1; i <= m; i ++){
		for(int j = 0; j < n; j ++){
			int k = Get(j, i - 1);
			Q[k].Pop(i - p);
			f[i] = max(f[i], Q[k].Front() + g[Get(j, 1)][i]);
		}
		for(int j = 0; j < n; j ++)
			Q[Get(j, i - 1)].Push(i, f[i] - g[Get(j, 1)][i] - a[j]);
	}
	printf("%d\n", f[m]);
	return 0;
}

标签:普及,int,max,NOIP2009,getchar,队列,while,include,P1070
来源: https://www.cnblogs.com/lpf-666/p/15083057.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有