码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P3295 [SCOI2016]萌萌哒 |倍增+并查集

时间:2020-01-14 23:55:24      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:cstring   merge   结果   限制   scan   区间   const   --   return   

题目描述

一个长度为 nnn 的大数,用 S1S2S3?SnS_1S_2S_3 \cdots S_nS1?S2?S3??Sn?表示,其中 SiS_iSi? 表示数的第 iii 位, S1S_1S1? 是数的最高位。告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2l_1,r_1,l_2,r_2l1?,r1?,l2?,r2?,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2?Sr1S_{l_1}S_{l_1+1}S_{l_1+2} \cdots S_{r_1}Sl1??Sl1?+1?Sl1?+2??Sr1??与Sl2Sl2+1Sl2+2?Sr2S_{l_2}S_{l_2+1}S_{l_2+2} \cdots S_{r_2}Sl2??Sl2?+1?Sl2?+2??Sr2??完全相同。

比如 n=6n=6n=6 时,某限制条件 l1=1,r1=3,l2=4,r2=6l_1=1,r_1=3,l_2=4,r_2=6l1?=1,r1?=3,l2?=4,r2?=6 ,那么 123123123123123123,351351351351351351 均满足条件,但是 120121201212012,131141131141131141 不满足条件,前者数的长度不为 666 ,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

输入格式

第一行两个数n和m,分别表示大数的长度,以及限制条件的个数。

接下来m行,对于第i行,有4个数 li1,ri1,li2,ri2,分别表示该限制条件对应的两个区间。

1≤n≤1051\le n\le 10^51≤n≤105,1≤m≤1051\le m\le 10^51≤m≤105 ,1≤li1,ri1,li2,ri2≤n 1\le li1,ri1,li2,ri2 \le n 1≤li1,ri1,li2,ri2≤n ;并且保证 ri1?li1=ri2?li2 ri1-li1=ri2-li2 ri1?li1=ri2?li2 。

输出格式

一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模 109+7 10^9+7 109+7 的结果即可。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int _=1e5+10,N=16,p=1e9+7,mod=1e9+7;
#define int long long
int n,m,f[22][_];
int get(int x,int y){
    return f[y][x]==x?x:f[y][x]=get(f[y][x],y);
}
bool vis[_];
inline int ksm(int x,int y){
    int res=1;
    while(y){
        if(y&1)res=res*x%mod; 
        x=x*x%mod; y>>=1;
    }
    return res;
}
void merge(int x,int y,int len){
  if(get(x,len)!=get(y,len))
    f[len][f[len][x]]=f[len][y];
}
signed main(){
    cin>>n>>m;
    for(int j=0;j<=21;j++)for(int i=1;i<=n;i++)f[j][i]=i;
    int l1,l2,r1,r2;
    for(int i=1;i<=m;i++){
        scanf("%lld%lld%lld%lld",&l1,&r1,&l2,&r2);
        for(int j=20;j>=0;j--)
        if(l1+(1<<j)-1<=r1)merge(l1,l2,j),l1+=1<<j,l2+=1<<j;
    }
    int ans=9,cnt=0;
    for(int j=20;j;j--)
    for(int i=1;i+(1<<j)-1<=n;i++)
    {merge(i,get(i,j),j-1);merge(i+(1<<(j-1)),f[j][i]+(1<<(j-1)),j-1);}
    for(int i=1;i<=n;i++)if(get(i,0)==i)cnt++;
    for(int i=1;i<cnt;i++)ans*=10,ans%=mod;
    cout<<ans<<endl;
}

luogu P3295 [SCOI2016]萌萌哒 |倍增+并查集

标签:cstring   merge   结果   限制   scan   区间   const   --   return   

原文地址:https://www.cnblogs.com/naruto-mzx/p/12194446.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!