ABC 304
在一个平面上有一块面积无限的蛋糕,给出 \(n\) 颗草莓的所在位置和 \(a\,(b)\) 条平行与 \(x\,(y)\) 轴的切刀位置。
切刀会把蛋糕沿 \(x\,(y)\) 轴切开。因此一共会切出 \((a+1)(b+1)\) 块蛋糕。
问:现在蛋糕上草莓数量最少的一块蛋糕,草莓数量是多少?最多的,又是多少?
用 lower_bound 计算出每一个草莓所属的行数和列数,然后用 map 维护草莓所在的块的草莓数量。
最小:如果有一块区域没有草莓,就是 0;否则在用 map 维护的时候就已经可以得出答案了。
给出一张图和一些点对 \((x_i,y_i)\)。
定义好图:每对 \((x_i,y_i)\),都不存在路径到达。
再给出一些询问 \((p,q)\),表示询问加上 \((p,q)\) 这条边后,图是否依然是好图。
考虑每对 \((x,y)\) 和每对 \((p,q)\) 所在的连通块。
给每个连通块一个编号,记 \(id[u]\) 为 \(u\) 所在的连通块编号。
只有满足 \((id[p],id[q])\) 和每对 \((id[x],id[y])\) 都不相同,图才能依然保持为好图。
有 \(n\) 天,给出一个长度为 \(n\) 的字符串 \(s\),表示小 A 的工作表,若为 #
则表示工作,反之为 .
则表示休息。
接下来,小 B 要决定他的工作表 \(t\)(也是 #
和 .
),对于一个 \(m\) 满足 \(m|n\),决定他的前 \(m\) 天的工作表,然后让第 \(i+m\) 天的工作情况和第 \(i\) 天一样,并且要求 \(n\) 天中每一天小 A 和小 B 都有至少一人工作,问共有多少种工作表的方案。
先枚举 \(m\) 为 \(n\) 的因数,\(O(\sqrt n)\),然后枚举 \(s\) 的每一个字符。如果 \(s[i]\) 为 .
,则 \(t[i\mod m]\) 必须为 #
。
假设 \(t\) 的前 \(m\) 个字符中还剩下 \(k\) 个可以为 .
的位置,这些位置可以随便选,有 \(2^k\) 中。
但是,还要减去重复的情况:当 \(m=8\) 的 #.#.#.#.
,可以在 \(m=4\) 的 #.#.
算一次。但又不能简单的减去,因为还有 \(m=2\) 的 #.
……
所以做个容斥。
int dfs(string s) //求出s中有多少重复的情况
{
int ans = 0;
for (int i = 1; i <= cnt; ++i) {
if (s.length() % a[i] != 0 || a[i] == s.length()) continue;
string t = "";
int x = 0;
for (int j = 0; j < a[i]; ++j) t += '.';
for (int j = 0; j < s.length(); ++j)
if (s[j] == '#') t[j % a[i]] = '#';
for (int j = 0; j < t.length(); ++j)
if (t[j] == '.') ++x;
ans = ((ans + qpow(2, x, mod) - dfs(t)) % mod + mod) % mod;
}
return ans;
}
int solve(string s) //求出基于s的t有多少方案
{
int ans = 0;
for (int i = 1; i <= cnt; ++i) {
if (s.length() % a[i] != 0 || a[i] == s.length()) continue;
string t = "";
int x = 0;
for (int j = 0; j < a[i]; ++j) t += '.';
for (int j = 0; j < s.length(); ++j)
if (s[j] == '.') t[j % a[i]] = '#';
for (int j = 0; j < t.length(); ++j)
if (t[j] == '.') ++x;
ans = ((ans + qpow(2, x, mod) - dfs(t)) % mod + mod) % mod;
}
return ans;
}