您的位置:首页 > 其它

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: