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

    【LG3295】[SCOI2016]萌萌哒

    题面

    洛谷

    题解

    考虑现在我们如果一次只是限定两个位置相等该怎么做,

    直接将这些位置用并查集并起来然后答案就是

    [ans= egin{cases} 10 & n=1\ 9 imes 10^{t-1} & ext{otherwise} end{cases} ]

    其中(t)为联通块的个数。

    现在我们是给定两个区间,我们将这两个区间中的数两两并起来算,复杂度(O(n^2))

    考虑优化上面的过程:

    维护(log n)个并查集,第(i)个并查集维护的是区间长度为(2^i)的区间相等的情况。

    那么我们每次只要合并两个并查集就行了。

    高层的并查集显然对下面的无影响,我们到最后将下层合并到上层,最后统计底层并查集联通块个数即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring> 
    #include <cmath> 
    #include <algorithm> 
    using namespace std; 
    inline int gi() { 
        register int data = 0, w = 1; 
        register char ch = 0; 
        while (!isdigit(ch) && ch != '-') ch = getchar(); 
        if (ch == '-') w = -1, ch = getchar(); 
        while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
        return w * data; 
    }
    const int Mod = 1e9 + 7; 
    const int MAX_N = 1e5 + 5; 
    int N, M, lg[MAX_N], bin[20];  
    int f[20][MAX_N]; 
    int getf(int *p, int x) { return p[x] == x ? x : p[x] = getf(p, p[x]); } 
    void merge(int len, int x, int y) { 
    	x = getf(f[len], x), y = getf(f[len], y); 
    	if (x != y) f[len][x] = y; 
    } 
    int main () { 
    #ifndef ONLINE_JUDGE 
        freopen("cpp.in", "r", stdin); 
    #endif 
    	N = gi(), M = gi();
    	if (N == 1) return puts("9") & 0; 
    	bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1; 
    	for (int i = 2; i <= N; i++) lg[i] = lg[i >> 1] + 1; 
    	for (int i = 0; bin[i] <= N; i++) 
    		for (int j = 1; j <= N; j++) f[i][j] = j; 
    	while (M--) { 
    		int l1 = gi(), r1 = gi(), l2 = gi(), r2 = gi(); 
    		int len = lg[r1 - l1 + 1]; 
    		merge(len, l1, l2);
    		merge(len, r1 - bin[len] + 1, r2 - bin[len] + 1); 
    	} 
    	for (int i = lg[N]; i; i--)
    		for (int j = 1; j + bin[i] - 1 <= N; j++) { 
    			merge(i - 1, j, getf(f[i], j));
    			merge(i - 1, j + bin[i - 1], getf(f[i], j) + bin[i - 1]); 
    		} 
    	int ans = 9, cnt = 0;
    	for (int i = 1; i <= N; i++) if (getf(f[0], i) == i) ++cnt; 
    	for (int i = 1; i < cnt; i++) ans = 10ll * ans % Mod; 
    	printf("%d
    ", ans); 
        return 0; 
    } 
    
  • 相关阅读:
    要成功先发疯
    情绪ABC理论
    树立和提高威信法
    javaagent
    sonar 使用
    sonar 代码质量管理
    四大思维工具,SWOT、PDCA、DISC、时间管理
    HyperLogLog
    位数组
    git checkout .和git checkout -f的区别;git add . git add -u git add -A的区别
  • 原文地址:https://www.cnblogs.com/heyujun/p/10542614.html
Copyright © 2011-2022 走看看