CF1830C Hyperregular Bracket Strings 题解

题目链接

[点击打开链接]( Hyperregular Bracket Strings "点击打开链接")

题目解法

很牛的题,只要是人类智慧的哈希我就是想不到/ll

一些性质是显然的(我们分析区间之间的关系):

  1. 区间包含,即 \(l1 \le l2\le r2\le r1\)
    \([l2,r2]\) 是合法的括号序列
    \([l1,l2-1]\)\([r2+1,r1]\) 合起来是合法的括号序列
  2. 区间相交但不包含,即 \(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;
}

posted @ 2024-02-12 11:43  Farmer_D  阅读(26)  评论(0)    收藏  举报