C. Longest Simple Cycle
题意:
有n条链,第i条链上有c[i]个点,a[i]为第i条链的顶点与第i-1条链的连接点,b[i]为第i条链的最后一个点与第i-1条链的连接点。通过上面的方法连接链会产生很多的环,问这些环的最大长度。
看样例
4
3 4 3 3
-1 1 2 2
-1 2 2 3
第二列共4个点,第二列最上面的点连接了第一列的点1(从上往下编号),第二列最下面的点连接了第一列的点2
最后建图得:
题解:
我们从右往左枚举环的左边界,
假设当前位置在i,当前环包含的点为sum(sum包含环从右边界到i-1位置的上下两个端点,此时还未闭环)
x和y分别记录a[i+1]和b[i+1]的最小值和最大值(即第i列的上下界)
开始分类讨论:
如果x == y,说明这个环结束了(闭环了),必须以i为新的右边界继续进行枚举
如果sum + x + c[i] - y +1 < c[i] 说明以i为新的右边界组成的环一定会大于原有的环(如果左边界在i的左边)。因此我们就舍弃原有的环,以i为右边界继续向左枚举答案
如果sum + x + c[i] - y +1 >= c[i] ,说明当前环比以i为右端点组成的新环更大,因此保留原有环,继续向左枚举。
枚举过程中记录最长闭环的长度
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <algorithm>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=1e5+5;
int a[N],b[N],c[N];
int main()
{int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&c[i]);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=n;i++) scanf("%d",&b[i]);LL ans=0,sum=0; //sum表示当前环包含的点数,ans记录环的最大值int x=1,y=c[n]; //与上述作用相同for(int i=n;i>1;i--) //从右往左进行枚举{if(x==y||sum+x+c[i]-y+1<c[i]) sum=c[i]; //符合条件1,3,以i为新的右边界来组成环,新环的初始长度为c[i]else sum+=x+c[i]-y+1; //符合条件2,继续使用原有环,并更新sum的长度,将i链加入sumx=min(a[i],b[i]);y=max(a[i],b[i]); //记录新的x,y值ans=max(ans,sum+y-x+1); //记录最大值}printf("%lld\n",ans); //注意,答案有可能爆int}return 0;
}