[SCOI2016]萌萌哒-题解

题目大意看原题面。

我们首先考虑,对于每个相等的数,我们用并查集将其并起来,那么由于不能有前导0,令最后集合的个数为 c c c,所以答案就是 9 × 1 0 c − 1 9\times 10^{c-1} 9×10c1,除了开头不能选0,只有9中选择方案外,其余的每个数字都有10种选择方案(只有一位数字的时候需要特判,因为此时0也算)。

由于暴力的合并的话,最坏的复杂度会达到 O ( n m l o g n ) O(nmlogn) O(nmlogn),就只有30分,那么由于每次都并的一整块,所以我们用倍增的方式,将一块一块二进制拆分后并起来,那么每次合并只需 O ( l o g 2 n ) O(log^2n) O(log2n)的时间,然后由于最后我们需要知道每一个元素属于哪个集合,所以在从大到小的将块拆开,推下去,最后就可以得知每个元素的所属集合,复杂度 O ( n l o g n ) O(nlogn) O(nlogn),所以最后看一下有多少个集合即可,最终复杂度为 O ( m l o g 2 n + n l o g n ) O(mlog^2n+nlogn) O(mlog2n+nlogn)

大的块拆分的方式如下:

lz

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1e9+7,Log=22;
const int M=1e5+10;
int n,m;
int f[M][Log];
int find(int a,int dis){return f[a][dis]==a?a:f[a][dis]=find(f[a][dis],dis);}
void init(){for(int i=0;i<Log;i++)for(int j=1;j<=n;j++)f[j][i]=j;}
void merge(int a,int b,int dis){
    int f1=find(a,dis),f2=find(b,dis);
    if(f1!=f2)f[f[a][dis]][dis]=f[b][dis];
}
ll ans=9ll;
ll fpow(ll a,ll b){
	ll res=1;
	for(;b;b>>=1,a=(a*a)%mod)
		if(b&1)res=(res*a)%mod;
	return res;
}
int l1,l2,r1,r2;
void file(){
    freopen("moe.in","r",stdin);
    freopen("moe.out","w",stdout);
}
void close(){
    fclose(stdin);
    fclose(stdout);
}
int cnt,now;
int main(){
    file();
    scanf("%d%d",&n,&m);
    if(n==1){puts("10");return 0;}
    init();
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        for(int j=Log-1;j>=0;j--){
            if(l1+(1<<j)-1<=r1)merge(l1,l2,j),l1+=(1<<j),l2+=(1<<j);
        }
    }
    for(int j=Log-1;j;j--){
        for(int i=1;i+(1<<j)-1<=n;i++){
            merge(i,find(i,j),j-1);
            merge(i+(1<<(j-1)),f[i][j]+(1<<(j-1)),j-1);
        }
    }
    for(int i=1;i<=n;i++)if(find(i,0)==i) cnt++;
    ans=ans*fpow(10,cnt-1)%mod;
    printf("%lld\n",ans);
    close();
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值