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坑了.......