CF集萃3
题意:给你一棵树,每个点被染成了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的更多相关文章
- CF集萃1
因为cf上一堆水题,每个单独开一篇博客感觉不太好,就直接放一起好了. CF1096D Easy Problem 给定字符串,每个位置删除要代价.求最小代价使之不含子序列"hard" ...
- CF集萃2
CF1155D - Beautiful Array 题意:给你一个序列和x,你可以选择任意一个子串(可以为空)乘上x,使得得到的序列最大子串和最大.求这个最大值.30w,2s. 解:设fi,0/1/2 ...
- 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 ...
- cf之路,1,Codeforces Round #345 (Div. 2)
cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅..... ...
- cf Round 613
A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个 ...
- ARC下OC对象和CF对象之间的桥接(bridge)
在开发iOS应用程序时我们有时会用到Core Foundation对象简称CF,例如Core Graphics.Core Text,并且我们可能需要将CF对象和OC对象进行互相转化,我们知道,ARC环 ...
- [Recommendation System] 推荐系统之协同过滤(CF)算法详解和实现
1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web ...
- 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 ...
- 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 ...
随机推荐
- 应用上云新模式,Aliware 全家桶亮相杭州云栖大会
全面上云带来的变化,不仅是上云企业数量上的攀升,也是企业对云的使用方式的转变,越来越多的企业用户不仅将云作为一种弹性资源,更是开始在云上部署架构和应用,借助 Serverless 等技术,开发人员只需 ...
- kubernetes配置(kubeconfig)对多集群的访问
配置对多集群的访问 本文展示如何使用配置文件来配置对多个集群的访问. 在将集群.用户和上下文定义在一个或多个配置文件中之后,用户可以使用 kubectl config use-context 命令快速 ...
- js面试总结3
异步和单线程 题目: 1.同步和异步的区别? 2.一个关于setTimeout的笔试题. 3.前段使用异步的场景有哪些? 什么是异步? console.log(100) setTimeout(func ...
- (转)Java ClassLoader详解
转:http://java.chinaitlab.com/base/804400.html 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一.它使得 Java 类可以被动态 ...
- RPC远程过程调用实例详解
1.创建IDL文件,定义接口. IDL文件可以由uuidgen.exe创建. 首先找到系统中uuidgen.exe的位置,如:C:\Program Files\Microsoft Visual Stu ...
- css3 鼠标悬浮动画效果
CSS3案例 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...
- Docker系列(二):Docker基础命令
docker的部署安装(Linux kernel至少3.8以上): yum install docker docker1.8安装:(下面 是两个命令) # cat >/etc/yum.repos ...
- Android Drawable 详解(教你画画!)
参考 1.Android中的Drawable基础与自定义Drawable 2.android中的drawable资源 3.Android开发之Shape详细解读 Drawable分类 No xml标签 ...
- JS中鲜为人知的问题: [] == ![]结果为true,而 {} == !{}却为false
console.log( [] == ![] ) // true console.log( {} == !{} ) // false 在比较字符串.数值和布尔值的相等性时,问题还比较简单.但在涉及到对 ...
- Luogu P2079 烛光晚餐(背包)
P2079 烛光晚餐 题意 题目背景 小明准备请小红去一家咖啡厅,共进烛光晚餐.小红高兴地和他一起去了咖啡厅. 题目描述 小红说:"小明,你点菜吧."小明看到菜单上有\(N\)道菜 ...