萌萌哒

题目大意:给出一个不定大数,给出一些限制条件,形如:区间l1,r1与l2,r2两个区间中所有的数相等,询问共有多少种合法的大数?

n<=1e5,m<=1e5

30分:

对于给出的区间限定条件,暴力枚举每一个点,利用并查集维护有相等关系的点,最后统计并查集个数,答案就是:9*10^(并查集个数-1)  因为第一个数不为零(他可不是序列。。。

时间复杂度:并查集看作常数,那么总复杂度O(nm),一个暴力。。。

100分:

观察暴力做法,发现维护点之间的对应关系时,暴力枚举的速度实在是太慢,但是我们还是需要知道每一个点的对应关系,所以我们考虑倍增加速。

我们在读入区间时利用二进制拆分将区间分解,再利用并查集合并,通过预处理,利用st表的思想(也不是st表,比较像而已。。。)维护f[i][j],表示从i开始往后2^j这个区间。

那么我们紧接着枚举base(base是2的指数),每一次将区间分一半,再将利用并查集合并,最后还是查询并查集个数(枚举st[i][0](代表每一个点))

时间复杂度:倍增确实是一个好东西,二进制拆分mlogn,区间平分nlogn,总复杂度nlogn(渐近复杂度)

最后:附上本题代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #define mod 1000000007
 5 #define LL long long    
 6 using namespace std;
 7 
 8 int n,m;
 9 LL fa[10000005],cnt,ans;
10 LL st[1000005][25],start[10000005];
11 
12 int find(int x)
13 {
14     if(fa[x]==x) return x;
15     return fa[x]=find(fa[x]);
16 }
17 void merge(int l1,int l2,int base)
18 {
19     int f1=find(st[l1][base]),f2=find(st[l2][base]);
20     if(f1>f2) swap(f1,f2);
21     fa[f2]=f1;
22 }
23 int main()
24 {
25     scanf("%d%d",&n,&m);
26     for(int j=0;j<=log2(n)+1;j++)
27     {
28         for(int i=1;i<=n;i++)
29         {
30             st[i][j]=++cnt;
31             start[cnt]=i;
32             fa[cnt]=cnt;
33         }
34     }
35     for(int i=1;i<=m;i++)
36     {
37         int l1,r1,l2,r2;
38         scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
39         for(int base=log2(n)+1;base>=0;base--)
40         {
41             if(l1+(1<<base)-1<=r1)
42             {
43                 merge(l1,l2,base);
44                 l1+=(1<<base);
45                 l2+=(1<<base);
46             }
47         }
48     }
49     for(int base=log2(n)+1;base>=1;base--)
50     {
51         for(int i=1;i+(1<<base)-1<=n;i++)
52         {
53             int f=find(st[i][base]),sta=start[f];
54             merge(i,sta,base-1);
55             merge(i+(1<<(base-1)),sta+(1<<(base-1)),base-1);
56         }
57     }
58     ans=9;
59     for(int i=2;i<=n;i++)
60     {
61         if(fa[st[i][0]]==st[i][0])
62         {
63             ans*=10;
64             ans%=mod;
65         }
66     }
67     printf("%lld\n",ans%mod);
68     return 0;
69 }

猜你喜欢

转载自www.cnblogs.com/yufenglin/p/10702797.html
今日推荐