[SCOI2016]萌萌哒
题目描述#
一个长度为 的大数,用 表示,其中 表示数的第 位, 是数的最高位。告诉你一些限制条件,每个条件表示为四个数,,即两个长度相同的区间,表示子串 与 完全相同。
比如 时,某限制条件 ,那么 , 均满足条件,但是 , 不满足条件,前者数的长度不为 ,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
数据范围
, , ;并且保证 。
solution
这题难想在用 ST 表优化并查集的合并过程(还是第一次见呢),感觉很好的例题,所以就跑来写题解了 /cy
表示以 为左端点,区间 其中 已经完成合并的 的祖先(还是具体看代码理解吧 /kk)
合并就类似 ST 表预处理的方式正常合并就好了。
复杂度:
code
/*Work by:Ariel_*/
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int mod = 1e9 + 7;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int N, M, f[MAXN][25];
int find(int x, int y) {return f[x][y] == x ? f[x][y] : f[x][y] = find(f[x][y], y);}
void merge(int x, int y, int len) {
int fx = find(f[x][len], len), fy = find(f[y][len], len);
f[f[fx][len]][len] = fy;
}
int main(){
N = read(), M = read();
for (int i = 1; i <= N; i++)
for (int j = 0; j <= 21; j++) f[i][j] = i;
for (int i = 1; i <= M; i++) {
int l1 = read(), r1 = read(), l2 = read(), r2 = read();
int len = log2(r1 - l1 + 1);
merge(l1, l2, len);
l1 = r1 - (1 << len) + 1, l2 = r2 - (1 << len) + 1;
merge(l1, l2, len);
}
for (int len = 21; len >= 1; len--) {
for (int i = 1; i + (1 << len) - 1 <= N; i++) {
int fa = find(i, len);
if(fa == i) continue;
merge(i, fa, len - 1);
merge(i + (1 << (len - 1)), fa + (1 << (len - 1)), len - 1);
}
}
long long Ans = 0;
for (int i = 1; i <= N; i++) {
if(f[i][0] == i) {
if(Ans == 0) Ans = 9;
else Ans = Ans * 10 % mod;
}
}
cout<<Ans;
puts("");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现