前言:
追着单调队列来的,写完发现题解的其他技巧蚌埠住了。
正题:
我们可以先对每个加速腔处理,将 $ e_i - d_i $(以下称为 $ d_i $)作为从 $ i $ 到 $ i+1 $ 的成本。因为我是单调队列的做法,显然难以处理环,于是可以断环成链,再做观察。
题目要求绕环一周,断成链后即为从 $ i $ 出发到达 $ i+n $。即要求对于 $ \forall k \in [i,i+n-1] $ 满足:
\[\sum ^{k}_ {j=i}d_j \ge 0 \]因此我们可以先处理成前缀和。设:
\[s_i = \sum ^{i} _ {j=1} d_i \]这样,条件就变成了对于 $ \forall k \in [i,i+n-1] $ 满足:
\[s_k - s_{i-1} \ge 0 \]然后发现,只要尝试 $ [i,i+n-1] $ 中 $ s_{min} $ 是否满足条件,就可以得出答案。于是就可以用单调队列维护最小值啦!至于要求编号最小的,可以从 $ 1 $ 递推至 $ n $,第一个满足条件的即为编号最小的。若递推至 $ n $ 之后仍然不满足条件,即为无解,输出Failed
即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define TP template<typename T>
#define TP_ template<typename T,typename ... T_>
TP void read(T &x)
{
x=0;int f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
x*=f;
}
TP_ void read(T &x,T_&...y){read(x);read(y...);}
TP void write(T x){if(x<0){putchar('-'),x=-x;}if(x>9)write(x/10);putchar(48+x%10);}
TP void writeln(T &x){write(x);puts("");}
TP void writesp(T &x){write(x);putchar(' ');}
TP_ void writeln(const T &x,T_ &...y){writesp(x);writeln(y...);}
typedef long long LL;
constexpr int N=1e6+5;
constexpr int inf=1e9;
LL s[N<<1];
LL d[N<<1];
int l,r,q[N<<1];
int main()
{
int T;read(T);
while(T--)
{
int n;read(n);
for(int i=1,x;i<=n;i++)
read(x),d[i]=x;
for(int i=1,x;i<=n;i++)
read(x),d[i]-=x,d[i+n]=d[i];
for(int i=1;i<=n*2;i++)//先处理为前缀和
s[i]=s[i-1]+d[i];
l=1;r=0;q[l]=0;
for(int i=1;i<=n;i++)//将1~n的范围提前处理
{
while(l<=r&&s[q[r]]>=s[i])r--;
q[++r]=i;
}
bool success=0;
for(int i=1;i<=n;i++)
{
while(l<=r&&q[l]<i)l++;//使队列中始终只有i~i+n-1的范围
if(s[q[l]]>=s[i-1])
{
writeln(i);//第一次满足条件即为最小的编号
success=1;//记录是否有答案
break;//直接跳出
}
while(l<=r&&s[q[r]]>=s[i+n])r--;
q[++r]=i+n;
}
if(!success)puts("Failed!");//没答案就输出Falied
}
return 0;
}
标签:满足条件,ch,int,void,TP,writeln,回旋,加速器
From: https://www.cnblogs.com/lofty2007/p/17730212.html