題解 CHSEQ22 【Chef and Favourite Sequence】
阿新 • • 發佈:2020-07-28
Solution Chef and Favourite Sequence
題目大意:給定一個長為\(n\)的全\(0\)序列,以及\(m\)個操作\([l,r]\),代表將區間\([l,r]\)翻轉。問通過這\(m\)個操作可以生成多少種不同的序列
並查集,線性基
分析:
最終序列實際上就是選擇的操作異或起來(把每個操作當做\([l,r]\)為\(1\),其它為\(0\)的序列)
實際上有一些操作是可以被其他操作表示出來的,被表示出來的操作都是無用的。(實際上就是求這個線性空間的基)
設剩餘操作有\(x\)個,那麼答案為\(2^x\)
求線性基顯然不能暴力求,考慮特殊性質,\(1\)
我們可以做一個差分,對\([l,r]\)的修改變成\(l,r+1\)兩點的修改
那麼可以用並查集來維護,每次合併\(l,r+1\),如果一個區間的端點\(l,r\)在同一集合說明它已經被表示出來了
如果一組操作有關顯然會形成一個環,也就是說我們不需要考慮操作的順序
#include <cstdio> #include <cctype> using namespace std; typedef long long ll; const int maxn = 1e5 + 100,mod = 1e9 + 7; inline int read(){ int x = 0;char c = getchar(); while(!isdigit(c))c = getchar(); while(isdigit(c))x = x * 10 + c - '0',c = getchar(); return x; } int f[maxn],n,m,ans; inline int mul(int a,int b){return (1ll * a * b) % mod;} inline int qpow(int a,int b){ int res = 1,base = a; while(b){ if(b & 1)res = mul(res,base); base = mul(base,base); b >>= 1; } return res; } inline int find(int x){ return x == f[x] ? x : f[x] = find(f[x]); } inline void merge(int x,int y){ x = find(x),y = find(y); f[x] = y; } int main(){ n = read(),m = read(); for(int i = 1;i <= n + 1;i++)f[i] = i; for(int l,r,i = 1;i <= m;i++){ l = read(),r = read() + 1; if(find(l) == find(r))continue; merge(l,r),ans++; } printf("%d\n",qpow(2,ans)); return 0; }