题解 CF1771B Hossam and Friends
大家好,我是 CQ-C2024 蒟蒻 CJH。
题意
给定 $n$ 个数和 $m$ 个关系,每个关系的 $x$ 和 $y$ 不能出现在同一段中,请问有多少个连续子段符合要求。
分析题目
设 $a_i$ 为以 $i$ 为起点能符合要求的最远的终点,显然每个初始的终点都为 $n$。
当每给出一个关系 $x$ 和 $y$ 时,我们更新 $a_x=\min(a_x,y-1)$。
意思就是以 $x$ 为起点,如果原来的终点比现在的终点远,那么更新,因为终点过了 $y-1$ 就不符合要求了。
处理完 $m$ 个要求之后,从大到小枚举 $1 \le i <n$ 更新 $a_i = \min(a_i,a_{i+1})$。因为在 $i$ 之前的值都会受到 $a_i$ 的限制。
所以最终答案为 $\sum\limits_{i=1}^n{a_i-i+1}$,一定要加一,因为一个数本身也是符合要求的一个段。
代码
//the code is from chenjh
#include<bits/stdc++.h>
using namespace std;
int a[100001];
void solve(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) a[i]=n;//能到的最远点设为 n。
int x,y;
while(m--){
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);//此操作保证 x<y。
a[x]=min(a[x],y-1);//更新答案。
}
for(int i=n-1;i>=1;i--)//从大到小!
a[i]=min(a[i],a[i+1]);//更新限制。
long long ans=0;
for(int i=1;i<=n;i++)
ans+=a[i]-i+1;//最远点减起点加一。
printf("%lld\n",ans);
}
int main(){
int t;scanf("%d",&t);
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号