2021.08.20 CF1552F Telepanting

CF1552F   Telepanting \color{green}{\texttt{CF1552F Telepanting}} CF1552F Telepanting

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

有一只初始在位置 0 0 0 的蚂蚁,它每秒钟会向右走 1 1 1 一个单位长度。

在地图上有 n n n 个虫洞,第 i i i 个虫洞在位置 x i x_{i} xi,如果它是活动的,它就会把蚂蚁送回到位置 y i ( y i < x i ) y_{i}(y_{i}<x_{i}) yi(yi<xi)

初始时每个虫洞有一个参数 s i s_{i} si s i s_{i} si 0 0 0 表示虫洞是初始静止的,而 1 1 1 表示虫洞初始是活动的。

当蚂蚁踩到虫洞 i i i 时:

  • 如果这个虫洞是静止的,那么此虫洞会变成活动的,但是蚂蚁的位置不改变。
  • 如果这个虫洞是活动,那么此虫洞将变成静止,且会把蚂蚁送回 y i y_{i} yi 位置,而接下来蚂蚁将保持向右每秒 1 1 1 个单位的速度前进(即下一秒它会到位置 y i + 1 y_{i}+1 yi+1)。

现在我们想知道,这只蚂蚁需要多少时间才能到位置 ( x n + 1 ) (x_{n}+1) (xn+1) 呢?答案对 998244353 998244353 998244353 取模

1 ≤ n ≤ 2 × 1 0 5 , ∀ i ∈ [ 1 , n ] , 1 ≤ y i < x i ≤ 1 × 1 0 9 , s i ∈ { 0 , 1 } 1 \leq n \leq 2 \times 10^{5},\quad \forall i \in [1,n], \quad 1 \leq y_{i}<x_{i} \leq 1 \times 10^{9},s_{i} \in \{0,1 \} 1n2×105,i[1,n],1yi<xi1×109,si{0,1}

保证 x 1 ⋯ n x_{1 \cdots n} x1n 严格递增

Translated by myself.

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

首先,如果这只蚂蚁到达了虫洞 i i i,那么代表它经过虫洞 1 ⋯ ( i − 1 ) 1 \cdots (i-1) 1(i1) 时,这些虫洞一定是静止的,同时,因为它经过了这些虫洞,所以现在 这些虫洞一定是活动的。

我们记 f i f_{i} fi 表示走到虫洞 i i i 并且被送回位置 y i y_{i} yi 后还需多少时间回到 x i x_{i} xi。显然对于所以 x j > y i x_{j}>y_{i} xj>yi 的虫洞 j ( j < i ) j(j<i) j(j<i) 都会有 f j f_{j} fj 的贡献(因为它们一定是活动的),加上从 y i y_{i} yi 走到 x i x_{i} xi 的时间,我们有:

f i = x i − y i + ∑ x j > y i , j < i f j f_{i}=x_{i}-y_{i}+\sum\limits_{x_{j}>y_{i},j<i}f_{j} fi=xiyi+xj>yi,j<ifj

很显然,因为题目说了 x 1 ⋯ n x_{1 \cdots n} x1n 是严格递增的,所以合法的 j j j 是集中在一个区间内的。所以我们可以用前缀和快速地维护 ∑ x j > y i , j < i f j \sum\limits_{x_{j}>y_{i},j<i} f_{j} xj>yi,j<ifj 这一串的值。

最后的答案就是:

∑ i = 1 n f i [ s i = 1 ] + x n + 1 \sum\limits_{i=1}^{n} f_{i}[s_{i}=1]+x_{n}+1 i=1nfi[si=1]+xn+1

前一半表示因为虫洞耽搁的时间,后一半( x n + 1 x_{n}+1 xn+1)表示没有虫洞直接走到 ( x n + 1 ) (x_{n}+1) (xn+1) 也必须要的时间。

总的时间复杂度: O ( n ) \mathcal{O}(n) O(n)。总的空间复杂度: O ( n ) \mathcal{O}(n) O(n)

[Code] \color{blue}{\texttt{[Code]}} [Code]

const int N=2e5+100;
const int mod=998244353;
long long f[N],pre[N],ans;
bool s[N];int x[N],y[N],n;
int main(){
	n=read();ans=0ll;
	for(int i=1;i<=n;i++){
		x[i]=read();y[i]=read();s[i]=read();
		int j=lower_bound(x+1,x+i+1,y[i])-x;
		f[i]=(x[i]-y[i]+pre[i-1]+mod-pre[j-1])%mod;
		ans+=s[i]?f[i]:0;pre[i]=pre[i-1]+f[i];
	}
	printf("%lld",(ans+x[n]+1)%mod);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值