QBXT2025S刷题 Day2
\(rk38\)
T1
这道题想了 \(1h\) 差不多。
这道题其实可以直接转化成选一个点,把覆盖着这个点线段全部删掉,使得左右两边都有线段。
可以维护每个点被多少个区间覆盖,左面有多少个区间,右面有多少个区间。
这个可以差分。
注意,\([1,6]\) 和 \([7, 8]\) 之间是没有点的,但是他们之间的那一段也得考虑。
因此我们可以把所有区间都乘以 \(2\),就相当于在他们中间插入一个点。
这是代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <ctime>
using std::cin;
using std::cout;
const int N = 8e5 + 10;
int l[(int)2e5 + 10];
int r[(int)2e5 + 10];
int rin[N];
int lin[N];
int cnt[N];
std::vector<int> p;
void read(int &x)
{
char c = getchar();
x = 0;
int f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -f;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
x = x * f;
}
int main()
{
int t;
read(t);
while (t--)
{
p.clear();
memset(lin, 0, sizeof(lin));
memset(rin, 0, sizeof(rin));
memset(cnt, 0, sizeof(cnt));
int n;
read(n);
for (int i = 1; i <= n; ++i)
{
read(l[i]);
read(r[i]);
p.push_back(l[i]);
p.push_back(r[i]);
}
std::sort(p.begin(), p.end());
p.erase(std::unique(p.begin(), p.end()), p.end());
int maxval = 0;
for (int i = 1; i <= n; ++i)
{
l[i] = std::lower_bound(p.begin(), p.end(), l[i]) - p.begin() + 1;
r[i] = std::lower_bound(p.begin(), p.end(), r[i]) - p.begin() + 1;
l[i] *= 2;
r[i] *= 2;
cnt[l[i]]++;
cnt[r[i] + 1]--;
maxval = std::max(maxval, r[i]);
}
for (int i = 1; i <= n; ++i)
{
rin[1]++;
rin[l[i]]--;
lin[r[i] + 1]++;
lin[maxval + 1]--;
}
int ans = 1e9 + 7;
for (int i = 1; i <= maxval; ++i)
{
cnt[i] += cnt[i - 1];
lin[i] += lin[i - 1];
rin[i] += rin[i - 1];
if (lin[i] && rin[i])
ans = std::min(ans, cnt[i]);
}
if (ans == 1e9 + 7)
cout << -1 << '\n';
else
cout << ans << '\n';
}
return 0;
}
T2
这道题有一个结论部分分,就是 \(q = 0\) 的时候。
考虑在第一列随便放,然后容易证明,后面 \(m - 1\) 列每一列要么和前一列一样,要么是前一列取反。
所以答案是 \(2^n * 2^{m - 1}\)。
然后在对第一个部分分暴力就行。
正解:
结论:\(a_{i,j} = a_{i - 1, j} \oplus a_{i, j - 1} \oplus a_{i - 1, j - 1}\)。
易推出:\(a_{i,j} = a_{1, 1}\oplus a_{i, 1}\oplus a_{1, j}\)。
因此,如果我们已经知道 \(a_{i,j}\)。
假设 \(a_{1, 1} = 0,1\)。
这个可以通过 \(\mathcal{2-SAT}\) 建边。
如果无解,就是 \(0\)。
如果有解,就是 \(2^{\frac{连通块个数}{2}}\)。
#include <iostream>
using std::cin;
using std::cout;
const int N = 6e5 + 10;
const int mod = 1e9 + 7;
int n, m, q;
int cnt;
int go[N << 1];
int pow2[N << 1];
int find(int x)
{
if (go[x] == x)
return x;
return go[x] = find(go[x]);
}
void merge(int x, int y)
{
x = find(x);
y = find(y);
if (x != y)
{
go[x] = y;
cnt--;
}
}
void read(int& x)
{
x = 0;
char c = getchar();
int f = 1;
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = x * 10 + c - '0';
c = getchar();
}
x = x * f;
}
int main()
{
int n, m, q;
read(n), read(m), read(q);
cnt = 2 * (n + m);
pow2[0] = 1;
for (int i = 1; i <= 2 * (n + m); ++i)
go[i] = i;
for (int i = 1; i <= 2 * (n + m); ++i)
pow2[i] = 1ll * pow2[i - 1] * 2 % mod;
cout << pow2[n + m - 1] << '\n';
bool f = true;
while (q--)
{
int x, y, c;
read(x), read(y), read(c);
if (!f)
{
cout << 0 << '\n';
continue;
}
merge(x, y + n + c * (n + m));
merge(x + n + m, y + n + (!c) * (n + m));
if (find(x) == find(x + n + m))
{
cout << 0 << '\n';
f = false;
}
else
cout << pow2[cnt / 2 - 1] << '\n';
}
return 0;
}
T3
第 \(3\) 个部分分可以输出字符串的大小。
结论:答案是
\(\displaystyle\sum^n_{d = 1}\dfrac{\lfloor\dfrac{n}{d}\rfloor}{\displaystyle\prod_{i \in colors} \text{cnt}_i!}\)。
T4
不会。
听不懂。


浙公网安备 33010602011771号