机房模拟20180815

T1

一开始看一眼想到dp,但是发现不管怎么优化都一直停留在n^2,就没有往下想了

最后发现正解是贪心

我们可以首先发现,如果说买入的价格低于卖出的价格才能够获得利润,否则拿在手里就亏了一个亿。

所以我们可以先用一个小根堆来维护所有的买入的价格,在遇到第i个商店的时候,我们可以先比较当前店的利润,如果它比小根堆里堆顶的那个数字大,就说明它可以获得利润,我们可以将答案中加上这个利润。

由于我们可以在一个商店里面既买又卖,所以说当前商店的价格可能最低, 我们要先入堆再进行查询

但是我们发现这样不一定是最优的,因为后面可能有价格更高的,卖出去更划算

那么我们可以换一个角度,假设当前赚的钱是x,那么如果我们之后用更好价格卖出当前物品,相当于失去了这次卖出的x(也就是获得了-x)的利润,而获得新的x’的利润

所以再将当前的利润也放入堆中,就满足最优性了

贴上代码

#include<queue>
#include<cstdio>
#include<algorithm>
#define LL long long
const int MAXN=1e5+5;
std::priority_queue<int>q;
int a[MAXN];
int b[MAXN];
int main()
{
	//std::freopen("buy.in","r",stdin);
	//std::freopen("buy.out","w",stdout);
	int n;
	std::scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		std::scanf("%d",a+i);
	}
	for(int i=1;i<=n;i++)
	{
		std::scanf("%d",b+i);
	}
	LL ans=0;
	for(int i=1;i<=n;i++)
	{
		q.push(-a[i]);
		int t=q.top();
		int x=-b[i];
		if(t>x)
		{
			q.pop();
			q.push(x);
			ans-=x-t;
		}
	}
	std::printf("%I64d\n",ans);
	return 0;
}//

T2

当天最水的一道题目,我们可以发现,当我们设i的前缀和为sum[i]的时候,以i结尾且满足长度条件的最大连续子段和f[i]=max(sum[i]-sum[k])(k为1~i中的所有合法点),sum[i]固定,于是我们要求的就变成了i-e到i-s中sum[k]的最小值

直接线段树或者单调队列就能秒杀

#include<cstdio>
#include<algorithm>
const int MAXN=1e6+5;
const int INF=1e9+7;
int a[MAXN];
int q[MAXN];
int head=1;
int tail=0;
int main()
{
	//std::freopen("invest.in","r",stdin);
	//std::freopen("invest.out","w",stdout);
	int n,s,e;
	std::scanf("%d%d%d",&n,&s,&e);
	for(int i=1;i<=n;i++)
	{
		std::scanf("%d",a+i);
		a[i]+=a[i-1];
	}
	q[tail++]=0;
	int ans=-INF;
	for(int i=s;i<=n;i++)
	{
		while(head<tail&&i-q[head]>e)
		{
			head++;
		}
		while(head<tail&&a[i-s]<a[q[tail-1]])
		{
			tail--;
		}
		q[tail++]=i-s;
		ans=std::max(ans,a[i]-a[q[head]]);
	}
	if(ans>=0)
	{
		std::printf("%d\n",ans);
	}
	else 
	{
		std::printf("0\n");
	}
	return 0;
}

T3(问题描述又臭又长,全是废话系列,不想看描述的可以直接往下翻看我的题意简述)

鉴于这个题目描述非常无聊,我们直接奔入正题

题目的意思是给你一个字符串和一个k,然后让你求出所有回文串的长度,然后将长度排个序,将前k个乘起来,结果取模

注意长度不去重且只计算奇回文串,偶回文不计,比如7,5,3,3,3,2,1,1,的话,前4个的乘积应该是7*5*3*3而不是7*5*3*1;

Manacher(基本裸题)

首先我们可以发现,题目的意思明显是让O(n)求出回文串及其长度,所以说我们可以自然而然的想到马拉车(Manacher)

求出每一个点的最大回文半径以后,做一个前缀和,用桶来装每一个回文长度的数量,然后倒着从大到小乘起来(注意k和cnt要 long long而且要用快速幂)

过的很轻松但是被long long坑了.......

猜你喜欢

转载自blog.csdn.net/Amuseir/article/details/81707333