学军中学第三届“图灵杯”趣味网络邀请赛——中级T4.欧拉回路 (图论,哈希)

题面

补题链接
在这里插入图片描述

7
5 6 7 1 2 3 3

在这里插入图片描述

13

在这里插入图片描述

5
30 50 10 30 70

在这里插入图片描述

8

在这里插入图片描述

题解

存在欧拉回路的条件是:1. 每个点的度数都是偶数。2. 有边的连通块最多一个。

数据范围是允许我们 n 2 n^2 n2 枚举的,因此我们看怎么均摊 O ( 1 ) O(1) O(1) 解决上面的两个判断。

首先,每个点的度数都是偶数。我们预处理两个 0/1 数组, p r e [ i ] [ j ] pre[i][j] pre[i][j] 表示只考虑前 i i i 个数,第 j j j 个数向后连边个数取模 2 的结果, s u f [ i ] [ j ] suf[i][j] suf[i][j] 表示只考虑后 n − i + 1 n-i+1 ni+1 个数,第 j j j 个数向前连边个数取模 2 的结果。

这两个数组都可以 O ( n 2 ) O(n^2) O(n2) 预处理出来,用 bitset 可以省点空间。然后,一个区间 [ l , r ] [l,r] [l,r] 满足度数需求,当且仅当数列 p r e [ r ] pre[r] pre[r] 异或数列 s u f [ l ] suf[l] suf[l] 后, [ l , r ] [l,r] [l,r] 以内全为 0 。异或后为 0,等价于相等。因此我们分别把 p r e [ r ] pre[r] pre[r] s u f [ l ] suf[l] suf[l] [ l , r ] [l,r] [l,r] 区间子序列哈希下来, O ( 1 ) O(1) O(1) 比较。安排一下枚举顺序,处理全部可以达到 O ( n 2 ) O(n^2) O(n2)

第二个条件,不太好办。但是我们可以发现一个规律:

  • 只要存在两条边 a − c   ,   b − d a-c~,~b-d ac , bd ,且满足 a < b < c < d a<b<c<d a<b<c<d ,那么 a , b , c , d a,b,c,d a,b,c,d 一定是连通的。

证明很简单,归纳 b b b c c c 数字的大小关系,会发现不论如何 a − b a-b ab b − c b-c bc 中有至少一条边存在。

所以,一段区间 [ l , r ] [l,r] [l,r] 满足第二个条件,当且仅当存在一个分界点 i ∈ [ l , r ) i\in [l,r) i[l,r) ,满足点 i i i 前面有边,后面有边,但没有边跨过 i i i i + 1 i+1 i+1 的中间线。

我们固定左端点,右端点往右枚举,大力讨论,维护最靠左的一个最大区间 [ L , R ] ⊆ [ l , r ] [L,R]\sube [l,r] [L,R][l,r] ,满足 [ L , R ] [L,R] [L,R] 以内都是分界点(暂假设后面都有边)。我们得提前处理出 p t [ i ] [ j ] pt[i][j] pt[i][j] ,表示 [ j , i ) [j,i) [j,i) 以内最靠左的位置,满足与 i i i 有边相连,没有则为 + ∞ +\infty +。这个可以 O ( n 2 ) O(n^2) O(n2) 预处理。

维护 [ L , R ] [L,R] [L,R] 讨论如下:当枚举到 r r r 时,令 l f = p t [ r ] [ l ] lf=pt[r][l] lf=pt[r][l]

  1. l f > r lf>r lf>r ,若区间为空,且前面出现过边,则赋值 [ L , R ] : = [ r − 1 , r ] [L,R]:=[r-1,r] [L,R]:=[r1,r],否则如果 R = r − 1 R=r-1 R=r1 ,则 R : = R + 1 R:=R+1 R:=R+1
  2. l f < r lf<r lf<r ,将右端点 R R R 尽量左移, R : = min ⁡ ( R , l f − 1 ) R:=\min(R,lf-1) R:=min(R,lf1) ,此时若 L > R L>R L>R(即区间为空),则赋值 [ L , R ] : = [ r , r ] [L,R]:=[r,r] [L,R]:=[r,r]

如果 [ L , R ] [L,R] [L,R] 为空,或者 R = r R=r R=r ,则子序列 [ l , r ] [l,r] [l,r] 满足第二个条件。时间复杂度 O ( n 2 ) O(n^2) O(n2)

CODE

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<ctime>
#include<queue>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 8005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define SI(x) set<x>::iterator
#define BI bitset<MAXN>
#define eps (1e-9)
LL read() {
	LL f=1,x=0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f*x;
}
void putpos(LL x) {
	if(!x) return ;
	putpos(x/10); putchar('0'+(x%10));
}
void putnum(LL x) {
	if(!x) putchar('0');
	else if(x < 0) putchar('-'),putpos(-x);
	else putpos(x);
}
const int MOD = 998344353;
const int bt = 23;
int n,m,s,o,k;
int a[MAXN];
BI pre[MAXN],suf[MAXN],f1[MAXN];
int pt[MAXN][MAXN];
int hs[MAXN],po[MAXN];
int main() {
	n = read();
	po[0] = 1;
	for(int i = 1;i <= n;i ++) {
		a[i] = read();
		po[i] = po[i-1] *1ll* bt % MOD;
	}
	for(int i = 1;i <= n;i ++) {
		pt[i][i+1] = n+2;
		for(int j = i;j > 0;j --) {
			pt[i][j] = pt[i][j+1];
			if(a[j] < a[i]) pt[i][j] = j,pre[i][j] = 1;
		}
		pre[i] ^= pre[i-1];
	}
	for(int i = n;i > 0;i --) {
		for(int j = i;j <= n;j ++) {
			if(a[j] > a[i]) {
				suf[i][j] = 1;
			}
			hs[j] = (hs[j] *1ll* bt % MOD + (int)pre[j][i]+2) % MOD;
		}
		suf[i] ^= suf[i+1];
		int has = 0;
		for(int j = i;j <= n;j ++) {
			(has += ((int)suf[i][j]+2) *1ll* po[j-i] % MOD) %= MOD;
			if(has == hs[j]) f1[i][j] = 1;
		}
	}
	int ans = 0;
	for(int i = 1;i <= n;i ++) {
		int l = n+3,r = n+2;
		for(int j = i;j <= n;j ++) {
			int lf = pt[j][i];
			if(lf > j) {
				if(l > r || (l == i-1 && r != j-1)) l = j-1,r = j;
				else if(r == j-1) r = j;
			}
			else {
				r = min(r,lf-1);
				if(l > r || l == i-1) l = r = j;
			}
			if(l > r || r == j || l < i) {
				ans += (int)f1[i][j];
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

后记

好家伙,居然是普及组比赛
在这里插入图片描述
3:18:51 过 T3,我还有救吗

posted @ 2021-08-08 16:28  DD_XYX  阅读(122)  评论(0编辑  收藏  举报