ARC082F - Sandglass(思维)

ARC082 D - Sandglass

Solution

这题睡觉的时候 想了挺久的。

一段时间 Δ t \Delta t Δt内要么是让 x + Δ t x+\Delta t x+Δt X X X m i n min min,要么是让 x − Δ t x-\Delta t xΔt 0 0 0 m a x max max

如果没有对边界取 m a x / m i n max/min max/min,就是一个单纯的前缀和了。而加上对边界取 m a x / m i n max/min max/min,对于没有撞到过边界的还是一个和之前一样的前缀和,但如果撞到过边界答案就会改变。

我们发现有这样一个性质:
对于 [ 0 , X ] [0,X] [0,X]的这一个区间经过若干次操作之后,会存在一个前缀和 0 0 0贴贴(指之后的值都和 0 0 0一样),存在一个后缀和 X X X贴贴(指之后的值都和 X X X一样)。

这个性质的来源可以通过下列过程得到:

  • 初始有一个区间 [ L , R ] = [ 0 , X ] [L,R]=[0,X] [L,R]=[0,X]表示还没有和 0 0 0 X X X贴贴的区间。
  • 若这一次是减的, [ L ′ , R ′ ] = [ L − Δ t , R − Δ t ] [L',R']=[L-\Delta t,R-\Delta t] [L,R]=[LΔt,RΔt],且 L ′ < 0 L'<0 L<0了,那么当前的 [ L ′ , 0 ) [L',0) [L,0)这一段值就和 0 0 0贴贴了,也就是说,初始区间中与 0 0 0贴贴的一部分前缀的长度增加 − L ′ -L' L
  • 若这一次是加的, [ L ′ , R ′ ] = [ L + Δ t , R + Δ t ] [L',R']=[L+\Delta t,R+\Delta t] [L,R]=[L+Δt,R+Δt],且 R ′ > X R'>X R>X了,那么当前的 ( X , R ′ ] (X,R'] (X,R]这一段值就和 0 0 0贴贴了,也就是说,初始区间中与 0 0 0贴贴的一部分前缀的长度增加 R ′ − X R'-X RX
  • 注:这里为了方便不会让正好等于 0 , X 0,X 0,X的数和 0 , X 0,X 0,X贴贴。
  • (是不是和 N O I P 2020    T 4 NOIP2020\;T4 NOIP2020T4的方法有异曲同工之妙?)

然后我们发现上述过程我们是可以直接模拟的,于是可以求出 a i , t a i a_i,ta_i ai,tai表示 [ 0 , a i ) [0,a_i) [0,ai)最早在 t a i ta_i tai时刻与 0 0 0贴贴,同样 b i , t b i b_i,tb_i bi,tbi表示与 X X X贴贴的我们也能求出来。

然后我们可以预处理 0 0 0的变化和 X X X的变化。
对于 ( x , y ) (x,y) (x,y)这个询问,如果 y y y x x x时刻之前和 0 0 0 X X X贴贴了,那就按照 0 / X 0/X 0/X之前预处理的答案算即可;如果没有,那么就表示 y y y x x x时刻之前从来没有撞到过 0 0 0 X X X的边界,因此再求一个前缀和计算就可以了。

时间复杂度 O ( n l g n ) O(nlgn) O(nlgn)

Code

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

using namespace std;

template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;

const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=600005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
int T[MAXN],numa=0,numb=0,s[MAXN],p0[MAXN],px[MAXN];
PR a[MAXN],b[MAXN];
signed main()
{
	int X=read(),n=read();
	for (int i=1;i<=n;i++) T[i]=read(); T[n+1]=INF+INF;
	int L=0,R=X;
	for (int i=1;i<=n+1;i++)
	{
		int t=T[i]-T[i-1];
		if (i&1) 
		{
			L-=t,R-=t;
			if (R<0) { numa++,a[numa]=MP(a[numa-1].fi+R-L+1,i); break; }
			else if (L<0) numa++,a[numa]=MP(a[numa-1].fi-L,i),L=0;
		}
		else
		{
			L+=t,R+=t;
			if (L>X) { numb++,b[numb]=MP(b[numb-1].fi+R-L+1,i); break; }
			else if (R>X) numb++,b[numb]=MP(b[numb-1].fi+R-X,i),R=X; 
		}
	}
	p0[0]=0,px[0]=X;
	for (int i=1;i<=n+1;i++)
	{
		int t=T[i]-T[i-1];
		if (i&1) s[i]=s[i-1]-t,p0[i]=max(p0[i-1]-t,0),px[i]=max(px[i-1]-t,0);
		else s[i]=s[i-1]+t,p0[i]=min(p0[i-1]+t,X),px[i]=min(px[i-1]+t,X);
	}
	int Case=read();
	while (Case--)
	{
		int x=read(),y=read(),p=lower_bound(T+1,T+n+2,x)-T-1,ans;
		if (y<a[numa].fi)
		{
			int t=lower_bound(a+1,a+numa+1,MP(y,-1))-a;
			if (T[a[t].se]>x) ans=y+s[p]+(x-T[p])*((p&1)?1:-1);
			else ans=p0[p]+(x-T[p])*((p&1)?1:-1);
		}
		else if (X-y<b[numb].fi)
		{
			int t=lower_bound(b+1,b+numb+1,MP(X-y,-1))-b;
			if (T[b[t].se]>x) ans=y+s[p]+(x-T[p])*((p&1)?1:-1);
			else ans=px[p]+(x-T[p])*((p&1)?1:-1);
		}
		upmin(ans,X),upmax(ans,0);
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值