POI2007 完结撒花!
旅游景点atr
很简单的一道 dp 题,不说了。有意思的是官网上的标程把空间复杂度压成了 \( 2^k \),而我不知道这是怎么搞的,所以官网上提交会 \( MLE \)
办公楼biu
很容易想到求补图的联通块,然后随便敲了个 \( BFS \),果断 \( WA \)
考虑用并查集把相同联通块的点圈起来,类似缩点的思想,这样一边枚举点一边减少点,可以卡着过
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
const int M = 2e6+5;
vector<int> g[N];
int n, m, a, b;
int col[N], cnt[N];
int fa[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int main() {
scanf("%d %d", &n, &m);
for (int _ = 1; _ <= m; _++) {
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
for (int i = 1; i <= n+1; i++) {
fa[i] = i;
}
int ans = 0;
for (int i = 1; i <= n; i = find(i+1)) {
queue<int> q;
q.push(i);
cnt[++ans] = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
fa[u] = find(u+1);
for (int i = 0; i < g[u].size(); i++) {
col[g[u][i]] = u;
}
for (int i = find(1); i <= n; i = find(i+1)) {
if (col[i] != u) {
fa[i] = find(i+1);
cnt[ans]++;
q.push(i);
}
}
}
}
printf("%d\n", ans);
sort(cnt+1, cnt+1+ans);
for (int i = 1; i <= ans; i++) {
printf("%d ", cnt[i]);
}
return 0;
}
细节见代码
树Drz
这题据说要用 9 个线段树,所以我没做。。。
对称轴osi
啊。。。这题初看不可捉的样子,然而千古神犇 vfk 说对称轴平分 360 角,利用这个结论就好捉了
当然类似无序运动那题搞个字符串也可以的(然而这两种方法都没有实现出来,太懒啦QWQ)
Zap
(好奇为什么没有中文)
(就叫它密码好了)
这题用到了神仙莫比乌斯函数的性质哦 QWQ
还顺带用到了分块
式子懒得敲咯,网上一大堆
代码留着吧,有点小技巧在里面的
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4+1;
int prime[N];
int mu[N], sum[N];
int t, n, m, d, ct;
bool not_prime[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
mu[1] = 1;
for (int i = 2; i < N; i++) {
if (!not_prime[i]) {
prime[++ct] = i;
mu[i] = -1;
}
for (int j = 1; j <= ct && i * prime[j] < N; j++) {
not_prime[i * prime[j]] = true;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i < N; i++) {
sum[i] = sum[i-1] + mu[i];
}
cin >> t;
while (t--) {
cin >> n >> m >> d;
if (n > m) {
swap(n, m);
}
n /= d, m /= d;
int ans = 0;
for (int i = 1, j = 1; i <= n; i = j + 1) {
j = min(n / (n / i), m / (m / i));
ans += (sum[j] - sum[i-1]) * (n / i) * (m / i);
}
cout << ans << endl;
}
return 0;
}
95%通过
可惜不知道为什么 \( TLE \) 了一个点 QWQ
山峰和山谷Grz
试机水题
大都市meg
据说可用 dfs + 树状数组水过
洪水pow
据说可用 dfs + 并查集水过
石头花园SKA
好神奇的推论题哦
从没想过要把石头放在同一边
而且也没想过要分四种情况
立方体大作战tet
贪心搞一搞咯
驾驶考试egz
呀,想歪了一点点
大概就是求两个 dp 数组然后滑动窗口搞一搞的咯
网上题解漫天飞
只留个还算美观的代码吧
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int c[N];
int n, m, p, k, x, h, d;
vector<int> pth[2][N], lis[2][N];
int bit[N], lf[N], rf[N];
int lowbit(int x) {
return x & -x;
}
int ask(int p) {
int ret = 0;
for (; p > 0; p -= lowbit(p)) {
ret = max(ret, bit[p]);
}
return ret;
}
void change(int p, int v) {
for (; p <= m; p += lowbit(p)) {
bit[p] = max(bit[p], v);
}
}
void run(int s, int d, int t, int *f) {
int ls = 0;
memset(bit, 0, sizeof(int)*(m+1));
for (int i = s, j = 2; j <= n; j++, i += d) {
for (int k = 0; k < pth[t][i].size(); k++) {
int ak = ask(pth[t][i][k])+1;
ls = max(ls, ak);
lis[t][i].push_back(ak);
}
for (int k = 0; k < lis[t][i].size(); k++) {
change(pth[t][i][k], lis[t][i][k]);
}
f[i] = !t ? i - 1 - ls : n - i - ls;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m >> p >> k;
m++;
for (int i = 1; i <= p; i++) {
cin >> x >> h >> d;
pth[d^1][x+d].push_back(m-h);
}
run(2, 1, 0, lf);
run(n-1, -1, 1, rf);
int ans = 0, buf = 0;
for (int i = 1, j = 1; i <= n; i++) {
while (j <= n && lf[j] + rf[i] <= k) {
j++;
}
ans = max(ans, j - i);
if (!lf[i] && !rf[i]) {
buf++;
}
}
cout << ans - buf << endl;
return 0;
}
丑丑的代码
天然气管道Gaz
呃。。。实在佩服 POI 的题目
水题硬生生想破脑袋
堆积木Klo
哇。。。听说这类问题有个很 NB 的名字叫二维偏序的。。。
当然还有大名鼎鼎的三维偏序。。。
dp 式子省略咯(反正网上满篇飞)
砝码Odw
orz 又是贪心,而且貌似很显然的样子
搞搞进位制就好了
四进制的天平Wag
呀,这个 dp 有意思哦
首先有几个贪心的推论要了解的
然后就可以大胆的 dp 啦(没错我还是抄的别人的代码)(所以不敢贴出来)
可怜的我只会推结论不会写 dp
而且结论貌似也很显然。。。
小结
每道不可捉的题背后都有一个可捉的推论。