CF1118F2 - Tree Cutting

题意:给你一棵树,每个点被染成了k种颜色之一或者没有颜色。你要切断恰k - 1条边使得不存在两个异色点在同一连通块内。求方案数。

解:对每颜色构建最小斯坦纳树并判交。我用的树上差分实现。

然后把同一颜色的点缩成一个点,在新树上树形DP,fx表示x子树内,x所在连通块内有一个关键点的方案数。hx表示x所在连通块内没有关键点的方案数。

 #include <bits/stdc++.h>

 const int N = , MO = ;

 struct Edge {
int nex, v, len;
}; int n, m, col[N], pw[N << ], fr[N], imp[N], K, stk[N], top, f[N], h[N];
std::vector<int> v[N]; inline void ERR() {
puts("");
exit();
return;
} struct G {
Edge edge[N << ]; int tp;
int e[N], d[N], fa[N], pos[N], num, ST[N << ][];
G(){}
inline void add(int x, int y, int z = ) {
edge[++tp].v = y;
edge[tp].len = z;
edge[tp].nex = e[x];
e[x] = tp;
return;
}
void DFS_1(int x, int f) {
d[x] = d[f] + ;
fa[x] = f;
pos[x] = ++num;
ST[num][] = x;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) continue;
DFS_1(y, x);
ST[++num][] = x;
}
return;
}
inline void pre1(int x = ) {
DFS_1(x, );
return;
}
inline void lcapre() {
for(int j = ; j <= pw[num]; j++) {
for(int i = ; i + ( << j) - <= num; i++) {
if(d[ST[i][j - ]] < d[ST[i + ( << (j - ))][j - ]]) {
ST[i][j] = ST[i][j - ];
}
else {
ST[i][j] = ST[i + ( << (j - ))][j - ];
}
}
}
return;
}
inline int lca(int x, int y) {
x = pos[x];
y = pos[y];
if(x > y) std::swap(x, y);
int t = pw[y - x + ];
if(d[ST[x][t]] < d[ST[y - ( << t) + ][t]]) {
return ST[x][t];
}
else {
return ST[y - ( << t) + ][t];
}
}
int recol(int x) {
int Col = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == fa[x]) {
continue;
}
int c = recol(y);
if(c && Col && c != Col) {
ERR();
}
if(c && !Col) {
Col = c;
}
}
if(col[x]) {
if(Col && col[x] != Col) {
ERR();
}
else {
Col = col[x];
}
}
col[x] = Col;
if(fr[x]) {
Col = ;
}
return Col;
}
inline int build_t(G &gr) {
/*printf("build virtue tree \n");
for(int i = 1; i <= K; i++) printf("%d ", imp[i]);
puts("\n");*/ stk[top = ] = imp[];
for(int i = ; i <= K; i++) {
int x = imp[i], y = lca(x, stk[top]);
while(top > && pos[y] <= pos[stk[top - ]]) {
gr.add(stk[top - ], stk[top], d[stk[top]] - d[stk[top - ]]);
top--;
}
if(y != stk[top]) {
gr.add(y, stk[top], d[stk[top]] - d[y]);
stk[top] = y;
}
stk[++top] = x;
}
while(top > ) {
gr.add(stk[top - ], stk[top], d[stk[top]] - d[stk[top - ]]);
top--;
}
return stk[top];
}
int cal(int x) {
int ans = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
int t = cal(y);
ans = 1ll * ans * t % MO * edge[i].len % MO;
}
return ans;
}
void DP(int x, int father) {
f[x] = col[x] ? : ;
h[x] = col[x] ? : ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == father) continue;
DP(y, x);
///
int t, t2;
t = 1ll * f[x] * (f[y] + h[y]) % MO + 1ll * f[y] * h[x] % MO;
t2 = 1ll * h[x] * (h[y] + f[y]) % MO;
f[x] = t % MO;
h[x] = t2;
}
//printf("x = %d f[x] = %d h[x] = %d \n", x, f[x], h[x]);
return;
}
}g[]; inline bool cmp(const int &a, const int &b) {
return g[].pos[a] < g[].pos[b];
} void out(int x, G &gr) {
for(int i = gr.e[x]; i; i = gr.edge[i].nex) {
int y = gr.edge[i].v;
if(y == gr.fa[x]) continue;
//printf("%d -> %d len = %d \n", x, y, gr.edge[i].len);
out(y, gr);
}
return;
} int main() { scanf("%d%d", &n, &m);
for(int i = ; i <= n * ; i++) pw[i] = pw[i >> ] + ;
for(int i = ; i <= n; i++) {
scanf("%d", &col[i]);
if(col[i]) {
v[col[i]].push_back(i);
}
} for(int i = ; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
g[].add(x, y);
g[].add(y, x);
}
g[].pre1();
g[].lcapre();
for(int i = ; i <= m; i++) {
//std::sort(v[i].begin(), v[i].end());
int len = v[i].size(), x = v[i][];
for(int j = ; j < len; j++) {
x = g[].lca(x, v[i][j]);
}
fr[x] = i;
} g[].recol(); /*for(int i = 1; i <= n; i++) {
printf("i = %d col = %d \n", i, col[i]);
}
puts("");*/ for(int x = ; x <= n; x++) {
//printf("x = %d \n", x);
for(int i = g[].e[x]; i; i = g[].edge[i].nex) {
int y = g[].edge[i].v;
//printf("%d -> %d \n", x, y);
if(!col[x] && !col[y]) {
g[].add(x, y);
//printf("g1 : add %d %d \n", x, y);
}
else if(!col[x]) {
g[].add(x, v[col[y]][]);
//printf("g1 : add %d %d \n", x, v[col[y]][0]);
}
else if(!col[y]) {
g[].add(v[col[x]][], y);
//printf("g1 : add %d %d \n", v[col[x]][0], y);
}
else if(col[x] != col[y]) {
g[].add(v[col[x]][], v[col[y]][]);
//printf("g1 : add %d %d \n", v[col[x]][0], v[col[y]][0]);
}
}
} g[].DP(v[][], ); printf("%d\n", f[v[][]]);
return ; g[].pre1(v[][]);
g[].lcapre(); /*printf("out G1 : \n");
out(v[1][0], g[1]);
puts("");*/ for(int i = ; i <= m; i++) {
imp[++K] = v[i][];
}
/*for(int i = 1; i <= n; i++) {
if(!col[i]) {
imp[++K] = i;
}
}*/ std::sort(imp + , imp + K + , cmp);
int rt = g[].build_t(g[]); //printf("out G2 : \n");
//out(rt, g[2]); int ans = g[].cal(rt);
printf("%d\n", ans);
return ;
}

AC代码

代码中有一些冗余部分....

CF1144G - Two Merged Sequences

题意:给你一个序列,你要把它拆成一个单增和一个单减序列。n <= 200000, 空间256M。

解:我一开始想到了一个2-sat + 主席树优化连边的做法,但是因为过高的空间复杂度导致MLE/RE.....

正解是DP,我们可以设fi表示第i个元素在上升序列中,下降序列的结尾最大值。gi反之。有4种转移。

 #include <bits/stdc++.h>

 const int N = ;

 int a[N], f[N], g[N], fr[N], gr[N], vis[N];

 int main() {
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
}
memset(g, 0x3f, sizeof(g));
memset(f, -, sizeof(f));
f[] = N, g[] = -;
for(int i = ; i <= n; i++) {
if(a[i - ] < a[i] && f[i] <= f[i - ]) {
f[i] = f[i - ];
fr[i] = ;
}
if(g[i - ] < a[i] && f[i] <= a[i - ]) {
f[i] = a[i - ];
fr[i] = ;
}
if(a[i - ] > a[i] && g[i] >= g[i - ]) {
g[i] = g[i - ];
gr[i] = ;
}
if(f[i - ] > a[i] && g[i] >= a[i - ]) {
g[i] = a[i - ];
gr[i] = ;
}
//printf("i = %d f = %d g = %d \n", i, f[i], g[i]);
} if(f[n] != -) {
printf("YES\n");
int t = ;
for(int i = n; i >= ; i--) {
vis[i] = t;
if(t == ) t = fr[i];
else t = gr[i];
}
for(int i = ; i <= n; i++) {
printf("%d ", vis[i] - );
}
return ;
}
if(g[n] != 0x3f3f3f3f) {
printf("YES\n");
int t = ;
for(int i = n; i >= ; i--) {
vis[i] = t;
if(t == ) t = fr[i];
else t = gr[i];
}
for(int i = ; i <= n; i++) {
printf("%d ", vis[i] - );
}
return ;
}
printf("NO\n");
return ;
}

AC代码

 #include <bits/stdc++.h>

 const int N = , lm = ;

 struct Edge {
int nex, v;
}edge[N]; int tp; int n, tot, e[N], ls[N], rs[N], dfn[N], low[N], num, a[], rt[], rt2[], rt3[], rt4[];
int fr[N], scc_cnt;
std::stack<int> S; inline void add(int x, int y) {
edge[++tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void tarjan(int x) {
low[x] = dfn[x] = ++num;
S.push(x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(!dfn[y]) {
tarjan(y);
low[x] = std::min(low[x], low[y]);
}
else if(!fr[y]) {
low[x] = std::min(low[x], dfn[y]);
}
}
if(low[x] == dfn[x]) {
int y;
++scc_cnt;
do {
y = S.top();
S.pop();
fr[y] = scc_cnt;
} while(x != y);
}
return;
} void insert(int &x, int y, int p, int id, int l, int r) {
if(!x || x == y) {
x = ++tot;
ls[x] = ls[y];
rs[x] = rs[y];
}
if(l == r) {
add(x, id);
if(y) add(x, y);
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
insert(ls[x], ls[y], p, id, l, mid);
}
else {
insert(rs[x], rs[y], p, id, mid + , r);
}
if(ls[x]) {
add(x, ls[x]);
}
if(rs[x]) {
add(x, rs[x]);
}
return;
} void Add(int id, int L, int R, int l, int r, int o) {
if(!o) return;
if(L <= l && r <= R) {
add(id, o);
return;
}
int mid = (l + r) >> ;
if(L <= mid) {
Add(id, L, R, l, mid, ls[o]);
}
if(mid < R) {
Add(id, L, R, mid + , r, rs[o]);
}
return;
} int main() {
printf("%d\n", (sizeof(e) * + sizeof(a) * ) / );
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
a[i]++;
} /// build
tot = n * ;
for(int i = ; i <= n; i++) {
if(i < n) {
insert(rt[i], rt[i - ], a[i], i + n, , lm);
}
if(i > ) {
Add(i, a[i], lm, , lm, rt[i - ]);
}
} for(int i = ; i <= n; i++) {
if(i < n) {
insert(rt2[i], rt2[i - ], a[i], i, , lm);
}
if(i > ) {
Add(i + n, , a[i], , lm, rt2[i - ]);
}
} for(int i = n; i >= ; i--) {
if(i > ) {
insert(rt3[i], rt3[i + ], a[i], i + n, , lm);
}
if(i < n) {
Add(i, , a[i], , lm, rt3[i + ]);
}
} for(int i = n; i >= ; i--) {
if(i > ) {
insert(rt4[i], rt4[i + ], a[i], i, , lm);
}
if(i < n) {
Add(i + n, a[i], lm, , lm, rt4[i + ]);
}
} for(int i = ; i <= tot; i++) {
if(!dfn[i]) {
tarjan(i);
}
} for(int i = ; i <= n; i++) {
if(fr[i] == fr[i + n]) {
puts("NO");
return ;
}
}
puts("YES");
for(int i = ; i <= n; i++) {
if(fr[i] < fr[i + n]) {
printf("0 ");
}
else {
printf("1 ");
}
}
puts("");
return ;
}

2-sat代码,仅供参考,不保证正确

CF1132E Knapsack

题意:给定8e16个物体,每个物体的体积在1 ~ 8中。求不超过W体积的情况下最接近W能得到多少体积。

解:考虑到答案要么是sum,要么不会小于W - 7,,而且由于物品体积都非常小所以随便调整几下就能得到解。

于是先贪心到W - 8以上,然后用bitset做正反两个背包,然后枚举答案判定即可。

 #include <bits/stdc++.h>

 typedef long long LL;

 const int N = ;

 std::bitset<N> f, g, h;
LL W, a[], b[]; int main() {
LL sum = ;
scanf("%lld", &W);
for(int i = ; i <= ; i++) {
scanf("%lld", &a[i]);
sum += a[i] * i;
}
if(sum <= W) {
printf("%lld\n", sum);
return ;
} sum = ;
for(int i = ; i <= ; i++) {
if(sum + a[i] * i <= W) {
sum += a[i] * i;
std::swap(a[i], b[i]);
}
else {
LL cnt = (W - sum) / i;
sum += cnt * i;
b[i] = cnt;
a[i] -= cnt;
break;
}
} f.set();
g.set();
for(int i = ; i <= ; i++) {
int lm = std::min(a[i], 100ll);
for(int j = ; j <= lm; j++) {
f |= f << i;
}
}
for(int i = ; i <= ; i++) {
int lm = std::min(b[i], 100ll);
for(int j = ; j <= lm; j++) {
g |= g << i;
}
} int delta = W - sum;
for(int i = delta; i >= ; i--) {
/// check if f-g = i
h = (g << i) & f;
if(h.any()) {
printf("%lld\n", i + sum);
return ;
}
} return ;
}

AC代码

CF

CF集萃3的更多相关文章

  1. CF集萃1

    因为cf上一堆水题,每个单独开一篇博客感觉不太好,就直接放一起好了. CF1096D Easy Problem 给定字符串,每个位置删除要代价.求最小代价使之不含子序列"hard" ...

  2. CF集萃2

    CF1155D - Beautiful Array 题意:给你一个序列和x,你可以选择任意一个子串(可以为空)乘上x,使得得到的序列最大子串和最大.求这个最大值.30w,2s. 解:设fi,0/1/2 ...

  3. ORA-00494: enqueue [CF] held for too long (more than 900 seconds) by 'inst 1, osid 5166'

    凌晨收到同事电话,反馈应用程序访问Oracle数据库时报错,当时现场现象确认: 1. 应用程序访问不了数据库,使用SQL Developer测试发现访问不了数据库.报ORA-12570 TNS:pac ...

  4. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  5. cf Round 613

    A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个 ...

  6. ARC下OC对象和CF对象之间的桥接(bridge)

    在开发iOS应用程序时我们有时会用到Core Foundation对象简称CF,例如Core Graphics.Core Text,并且我们可能需要将CF对象和OC对象进行互相转化,我们知道,ARC环 ...

  7. [Recommendation System] 推荐系统之协同过滤(CF)算法详解和实现

    1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web ...

  8. CF memsql Start[c]UP 2.0 A

    CF memsql Start[c]UP 2.0 A A. Golden System time limit per test 1 second memory limit per test 256 m ...

  9. CF memsql Start[c]UP 2.0 B

    CF memsql Start[c]UP 2.0 B B. Distributed Join time limit per test 1 second memory limit per test 25 ...

随机推荐

  1. JS继承(简单理解版)

    童鞋们,我们今天聊聊js的继承,关于继承,平时开发基本用不到,但是面试没有不考的,我就想问,这是人干的事吗? 好吧,迫于社会主义核心价值观,我们今天就来简单说一说js的继承,谁让它是面向对象编程很重要 ...

  2. axios HTTP 400后,error没有详细信息

    参考网址:axios怎么获取到error中的状态值,具体信息 error.response

  3. day23_4_hashlib

    #!/usr/bin/env python # -*- coding:utf-8 -*- # ----------------------------------------------------- ...

  4. Python中%r和%s的详解及区别_python_脚本之家

    Python中%r和%s的详解及区别_python_脚本之家 https://www.jb51.net/article/108589.htm

  5. Python 实现0-1背包

    代码: import numpy as np c=10 #背包容量 w=[2,2,6,5,4] #物品重量 v=[5,3,5,4,6] #物品价值 flag =[0,0,0,0,0] m=np.zer ...

  6. CentOS中GDB提示Missing separate debuginfos解决办法

    安装debuginfo 修改文件 vi /etc/yum.repo.d/CentOS-Debuginfo.repo 修改enabled的值为1 使用debuginfo-install安装需要的文件

  7. MyBatis - 常用标签与动态Sql

    MyBatis常用标签 ● 定义sql语句:select.insert.delete.update ● 配置JAVA对象属性与查询结构及中列明对应的关系:resultMap ● 控制动态sql拼接:i ...

  8. <Django> MVT三大块之view(视图)

    1.视图简介 作用:接受web请求,返回web响应 本质:一个函数,定义在views.py文件中(定义在其他地方也行,约定俗成) 流程:(如果匹配不到,报一个404错误)-----结果返回http r ...

  9. printk函数打开和关闭消息

    在驱动开发的早期, printk 非常有助于调试和测试新代码. 当你正式发行驱动时, 换句 话说, 你应当去掉, 或者至少关闭, 这些打印语句. 不幸的是, 你很可能会发现, 就在你 认为你不再需要这 ...

  10. LINUX用户和用户组操作命令

    Id Finger Pwck 检查/etc/passwd配置文件内的信息与实际主文件夹是否存在,还可比较/etc/passwd和/etc/shadow的信息是否一致,另外如果/etc/passwd中的 ...