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

    Description

    (mathrm{bzoj}) 上的题面太毒瘤了,重写一下。

    一个长度为 (n) 的大数,用 (S_1,S_2,S_3cdots S_n) 表示,其中 (S_i) 表示数的第 (i) 位, (S_1) 是数的最高位,告诉你一些限制条件,每个条件表示为四个数, (l_1,r_1,l_2,r_2) ,即两个长度相同的区间,表示子串 (S_{l_1}, S_{l_1+1}, S_{l_1+2}cdots S_{r_1})(S_{l_2}, S_{l_2+1},S_{l_2+2}cdots S_{r_2}) 完全相同。比如 (n=6) 时,某限制条件 (l_1=1,r_1=3,l_2=4,r_2=6) ,那么 (123123)(351351) 均满足条件,但是 (12012)(131141) 不满足条件,前者数的长度不为 (6) ,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

    答案模 (10^9+7)

    (1le n,mle 10^5,r_1-l_1=r_2-l_2)

    Solution

    好题!这题的做法太 (mathrm{tm}) 妙了!我被 (mathrm{vanillayi}) 巨巨吊打!我天天被吊打!

    我们先来考虑暴力怎么做(菜鸡 (mathrm{azi}) 连暴力都写错)。显然相等关系可以用并查集来维护,就像这样:

    while(m--) {
        int l1 = read(), r1 = read(), l2 = read(), r2 = read(), len = r1 - l1 + 1;
        rep(i, 0, len - 1) merge(l1 + i, l2 + i);
    }
    

    最后答案就是 (9 imes 10^{集合个数 - 1})

    但是这样是 (nm) 的,会挂。但是花爸爸说这玩意儿可以卡过去。

    我们面向数据范围编程可以猜测,这道题的算法应该是 (mlog n) 之类的什么玩意儿。

    线段树?好像没法合并。

    于是我们 (mathrm{vanillayi}) 大爷想到了倍增。

    我们使用一个奇妙的科技叫做倍增并查集,有点类似于 (mathrm{ST}) 表。

    (fa[x][y]) 表示 (left[x,x+2^y-1 ight]) 这一块的“父亲”是谁。

    对于第 (i) 个限制,设 (k=leftlfloor log_2len_i ight floor) 那么我们就可以将 ([l_{1_i},l_{1_i}+2^k-1]) 这一块的父亲置为 ([l_{2_i},l_{2_i}+2^k-1]) ,将 ([r_{1_i}-2^k+1,r_{1_i}]) 的父亲置为 ([r_{2_i}-2^k+1,r_{2_i}]) ,递归处理内部。

    统计答案同暴力,挂一个快速幂。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define N 100001
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define P 1000000007
    #define ll long long
    
    inline int read() {
    	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
    }
    
    int n, m, fa[N][17];
    
    int find(int x, int y) { return x == fa[x][y] ? x : fa[x][y] = find(fa[x][y], y); }
    void merge(int x, int y, int k) {
    	int fx = find(x, k), fy = find(y, k); if (fx == fy) return;
    	fa[fx][k] = fy;
    	if (k--) merge(x, y, k), merge(x + (1 << k), y + (1 << k), k);
    }
    inline ll quickPow(ll a, int k) { ll ret = 1; for (; k; k >>= 1, (a *= a) %= P) if (k & 1) (ret *= a) %= P; return ret; }
    int main() {
    	n = read(), m = read();
    	rep(i, 1, n) rep(j, 0, 17) fa[i][j] = i;
    	while (m--) {
    		int l1 = read(), r1 = read(), l2 = read(), r2 = read(), k = 0;
    		while ((1 << k) <= r1 - l1 + 1) k++; k--;
    		merge(l1, l2, k), merge(r1 - (1 << k) + 1, r2 - (1 << k) + 1, k);
    	}
    	int cnt = -1; rep(i, 1, n) cnt += (fa[i][0] == i);
    	printf("%lld", 9ll * quickPow(10, cnt) % P);
    	return 0;
    }
    
  • 相关阅读:
    请编程遍历页面上所有TextBox控件并给它赋值为string.Empty?
    AJAX基本应用
    EasyNVR录像开启后,无录像文件生成,如何解决?
    EasyNVR近期功能点优化及问题更新调整
    Linux下测试新版EasyNVR采用WebRTC播放起播较慢优化过程
    EasyNVR添加新用户无法查看历史录像问题原因分析
    EasyNVR查看直播视频流显示黑屏原因排查
    EasyNVR播hls格式视频无法全屏自适应播放如何调节?
    EasyNVR分屏切换时视频源丢失问题的优化分享
    EasyNVR通道设置中水印无法回显以及显示图片异常的问题优化
  • 原文地址:https://www.cnblogs.com/aziint/p/8542494.html
Copyright © 2011-2022 走看看