[SCOI2016]萌萌哒
https://www.luogu.com.cn/problem/P3295
题面
求字符串的个数,满足有若干种形如\(l1,r1,l2,r2\)的要求,使\(S_{l1,r1}=S_{l2,r2}\)
分析
显然,如果知道哪些字符相同,答案为\(9\times 10^{size-1}\)
考虑用并查集维护
\(\because\) 该操作具有可加性和可分裂性
\(\therefore\) 一个神仙的想法:倍增
可以将其分成若干层
\[[1,1+2^k),[2,2+2^k),\cdot\cdot\cdot \\
[1,1+2^{k-1}),[2,2+2^{k-1}),\cdot\cdot\cdot\\
[1,1+2^{k-2}),[2,2+2^{k-2}),\cdot\cdot\cdot\\
\cdot\cdot\cdot\cdot\cdot\cdot
\]
然后对每一层维护一个并查集,表示该区间与另一端区间是否完全相同,然后从上往下做一遍即可
#include<bits/stdc++.h>
#define ll long long
const int p=1e9+7;
using namespace std;
const int N=2e5+5;
int n,m,ans;
struct A{
int f[N];
inline int find(int x) {
int r=x,u;
while(f[r]!=r) {
r=f[r];
}
while(x!=r) {
u=x;
x=f[x];
f[u]=r;
}
return r;
}
inline void mer(int x,int y) {
int u=find(x),v=find(y);
if(u!=v) f[v]=u;
}
}tr[20];
int main() {
scanf("%d%d",&n,&m);
for(int i=0;i<=16;i++) {
for(int j=1;j<=n;j++) {
tr[i].f[j]=j;
}
}
for(int i=1;i<=m;i++) {
int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
for(int j=16;j>=0;j--) {
if(l1+(1<<j)-1<=r1) {
tr[j].mer(l1,l2);
l1+=(1<<j),l2+=(1<<j);
}
}
}
for(int i=16;i;i--) {
for(int j=1;j<=n;j++) {
int r=tr[i].find(j);
tr[i-1].mer(r,j),tr[i-1].mer(r+(1<<i-1),j+(1<<i-1));
}
}
for(int i=1;i<=n;i++) {
if(tr[0].find(i)==i) ans=!ans?9:(ll)ans*10%p;
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号