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

[SCOI2016]萌萌哒

时间:2019-04-13 00:54:11      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:最大   printf   复杂度   不能   class   name   can   拆分   dash   

Luogu P3295

mrclr两周前做的题让蒟蒻的我现在做?

第一眼组合计数,如果把数字相同的数位看作一个整体,除了第一位不能为零,剩下的每一位都有$0$~$9$十种。

设不同的位数为$x$,那么答案即为$9*10^x-1$

给出两段相同的区间,可以把它们看作单独的一位一位对应,用并查集把它们合并。

复杂度为$O(n^2)$。

考虑优化。发现修改操作有$n$次,查询只有$1$次。

把复杂度平衡一下。合并区间时,直接将大区间合并,最后将合并标记从大到小下传。

这样,合并的复杂度变小,查询的复杂度变大了。用倍增——也就是二进制拆分的做法,可以让修改、查询的复杂度都变为$O(nlogn)$

$fa[x][i]$表示从$x$开始,长度为$2^i$的区间的父亲(区间),

合并时,将一段区间用二进制拆分成若干个区间并合并;

最后查询时,从最大的区间长度开始枚举,将$[x][i]$的左右两半区间分别与$[x][i]$的父亲区间的左右两半区间合并。

void pushdown() {
    for(int j = 20; j; j--)
        for(int i = 1; i+(1<<j)-1 <= n; i++) {
            int ii = getfa(i,j);
            merge(i,ii,j-1); //左一半 
            merge(i + (1<<(j-1)),ii + (1<<(j-1)),j-1);//右一半
        }
}

 

最后查询并查集个数即可w

代码如下

 

技术图片
#include<cstdio>
#include<iostream>
#define MogeKo qwq
#define ll long long
using namespace std;
const int maxn = 1e5+10;
const ll mod = 1e9+7;

int n,m,fa[maxn][25];
int l1,l2,r1,r2;
ll cnt;

ll qpow(ll a,ll b) {
    ll ans = 1;
    ll base = a;
    while(b) {
        if(b&1) (ans *= base) %= mod;
        (base *= base) %= mod;
        b >>= 1;
    }
    return ans%mod;
}

void init() {
    for(int i = 1; i <= n; i++)
        for(int j = 0; j <= 20; j++)
            fa[i][j] = i;
}

int getfa(int x,int k) {
    if(fa[x][k] == x)return x;
    return fa[x][k] = getfa(fa[x][k],k);
}

void merge(int x,int y,int k) {
    int xx = getfa(x,k);
    int yy = getfa(y,k);
    fa[xx][k] = yy;
}

void pushdown() {
    for(int j = 20; j; j--)
        for(int i = 1; i+(1<<j)-1 <= n; i++) {
            int ii = getfa(i,j);
            merge(i,ii,j-1);
            merge(i + (1<<(j-1)),ii + (1<<(j-1)),j-1);
        }
}

int main() {
    scanf("%d%d",&n,&m);
    if(n == 1) {
        printf("10");
        return 0;
    }
    init();
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d%d",&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);
            }
    }
    pushdown();
    for(int i = 1; i <= n; i++)
        if(fa[i][0] == i)cnt++;
    printf("%lld",(9*qpow(10,cnt-1))%mod);
    return 0;
}
View Code

 

[SCOI2016]萌萌哒

标签:最大   printf   复杂度   不能   class   name   can   拆分   dash   

原文地址:https://www.cnblogs.com/mogeko/p/10699278.html

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