CF1830C Hyperregular Bracket Strings 题解
题目链接
[点击打开链接]( Hyperregular Bracket Strings "点击打开链接")
题目解法
很牛的题,只要是人类智慧的哈希我就是想不到/ll
一些性质是显然的(我们分析区间之间的关系):
- 区间包含,即 \(l1 \le l2\le r2\le r1\)
\([l2,r2]\) 是合法的括号序列
\([l1,l2-1]\) 和 \([r2+1,r1]\) 合起来是合法的括号序列 - 区间相交但不包含,即 \(l1 \le l2\le r1\le r2\)
\([l1,l2-1]\),\([l2,r1]\),\([r1+1,r2]\) 都是合法的括号序列
考虑如何体现这些性质,即我们需要把序列分成最小的区间单位(这东西表述出来是麻烦的,如果要真正去写也是很难写的)
异或哈希!!!
可以发现,哈希相同的位置一定属于一个最小的单位
所以对于哈希相同的位置把卡特兰数乘起来就是答案了
时间复杂度 \(O(n)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
const int N=300100,P=998244353;
int fac[N<<1],ifac[N],inv[N],cat[N];
int bin(int x,int y){ return 1ll*fac[x]*ifac[y]%P*ifac[x-y]%P;}
int qmi(int x,int y){
int res=1;
for(;y;y>>=1){ if(y&1) res=1ll*res*x%P;x=1ll*x*x%P;}
return res;
}
void comb(int n){
fac[0]=1;F(i,1,2*n) fac[i]=1ll*fac[i-1]*i%P;
ifac[n]=qmi(fac[n],P-2);DF(i,n-1,0) ifac[i]=1ll*ifac[i+1]*(i+1)%P;
F(i,1,n) inv[i]=1ll*fac[i-1]*ifac[i]%P;
F(i,1,n/2) cat[i<<1]=1ll*bin(i<<1,i)*inv[i+1]%P;
}
ull ha[N];
map<ull,int> cnt;
mt19937 mrand(chrono::steady_clock::now().time_since_epoch().count());
ull RAND(){ return 1ull*mrand()*mrand();}
void work(){
int n=read(),k=read();
F(i,1,n) ha[i]=0;
F(i,1,k){
int l=read(),r=read();
ull v=RAND();
ha[l]^=v,ha[r+1]^=v;
}
F(i,1,n) ha[i]^=ha[i-1];
cnt.clear();
F(i,1,n) cnt[ha[i]]++;
int ans=1;
for(auto it:cnt) ans=1ll*ans*cat[it.second]%P;
printf("%d\n",ans);
}
int main(){
comb(N-1);
int T=read();
while(T--) work();
return 0;
}

浙公网安备 33010602011771号