bzoj 4569: [Scoi2016]萌萌哒
2017-11-07 07:54
337 查看
题意:
有一个n位长的数,现在有些限制,即l1~r1与l2~r2的数完全相同。问有多少这样的数。题解:
显然无脑的做法是用并查集将对应位置分别连起来,最后看有多少联通块,算一下。但是明显会超时。用一个牛逼的做法,有点像线段树优化建图,就是每次倍增将2i长的段合并,最后扫一遍再将左边2i−1和右边2i−1的合并。
code:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #define LL long long using namespace std; LL fa[18][1800005]; const LL mod=1000000007; LL n,m; LL findfa(LL x,LL op) { if(fa[op][x]!=x) fa[op][x]=findfa(fa[op][x],op); return fa[op][x]; } void merge(LL x,LL y,LL op) { LL tx=findfa(x,op),ty=findfa(y,op); if(tx==ty) return; if(tx>ty) swap(x,y),swap(tx,ty); fa[op][ty]=tx; } LL fow(LL a,LL b) { LL ans=1; while(b) { if(b&1) (ans*=a)%=mod; (a*=a)%=mod;b>>=1; } return ans; } int main() { scanf("%lld %lld",&n,&m); for(LL k=0;k<=17;k++) for(LL i=1;i<=n;i++) fa[k][i]=i; while(m--) { LL l1,r1,l2,r2;scanf("%lld %lld %lld %lld",&l1,&r1,&l2,&r2); LL x=l1,y=l2; for(LL i=17;i>=0;i--) if((1<<i)<=(r1-x+1)) merge(x,y,i),x+=(1<<i),y+=(1<<i); } for(LL k=17;k>=1;k--) for(LL i=1;i<=n;i++) if(findfa(i,k)!=i) { LL tx=findfa(i,k); merge(tx,i,k-1);merge(tx+(1<<(k-1)),i+(1<<(k-1)),k-1); } LL num=0; for(LL i=1;i<=n;i++) if(findfa(i,0)==i) num++; printf("%lld",9*fow(10,num-1)%mod); }
相关文章推荐
- [bzoj4569][SCOI2016]萌萌哒
- BZOJ 4569: [Scoi2016]萌萌哒
- bzoj4569: [Scoi2016]萌萌哒
- BZOJ 4569: [Scoi2016]萌萌哒
- BZOJ 4569: [Scoi2016]萌萌哒 并查集+倍增
- BZOJ4569 [SCOI2016]萌萌哒 【并查集 + 倍增】
- 【BZOJ4569】[Scoi2016]萌萌哒(并查集+st表)
- BZOJ 4569: [Scoi2016]萌萌哒
- bzoj4569 [Scoi2016]萌萌哒 (st表 维护 并查集)
- BZOJ 4569: [Scoi2016]萌萌哒 倍增思维并查集
- 【bzoj4569】【SCOI2016】【萌萌哒】【st表+并查集】
- BZOJ 4569: [Scoi2016]萌萌哒 ST表 并查集
- BZOJ 4569 [Scoi2016]萌萌哒 | ST表 并查集
- BZOJ 4569 [Scoi2016] 萌萌哒
- bzoj 4569: [Scoi2016]萌萌哒
- [BZOJ4569][Scoi2016]萌萌哒(并查集+ST表)
- bzoj 4569: [Scoi2016]萌萌哒
- [BZOJ4569][SCOI2016]萌萌哒
- bzoj 4569 [Scoi2016]萌萌哒
- 【BZOJ 4569】 4569: [Scoi2016]萌萌哒 (倍增+并查集)