zoukankan      html  css  js  c++  java
  • [SCOI2016]萌萌哒

    Luogu P3295

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

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

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

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

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

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

    有效的修改操作最多只有$n-1$次,所以一定有重复的操作。

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

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

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

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

    最后查询时,从最大的区间长度开始枚举,将$[x][i]$的左右两半区间分别与$fa[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
  • 相关阅读:
    61. 最长不含重复字符的子字符串
    60. 礼物的最大价值 (未理解)
    59. 把数字翻译成字符串
    58. 把数组排成最小的数
    57. 数字序列中某一位的数字 (不懂)
    spring data jpa 官方文档
    idea 编译报错 源发行版 1.8 需要目标发行版 1.8
    idea maven 依赖报错 invalid classes root
    solr
    spring boot 官方文档
  • 原文地址:https://www.cnblogs.com/mogeko/p/10699278.html
Copyright © 2011-2022 走看看