暑假集训csp提高模拟18
赛时 rank21,T1 20pts,T2 0,T3 0,T4 0
学DSU On Tree学傻了,T3寄。
这几次模拟赛一次比一次离谱,一开始还都可以做做,后来一场偶尔有一道不可做,现在直接上俩黑一紫了
T1 Mortis
考虑到排序后的位置是知道的。
我们此时有如下几种情况
- 有
放反(如 ),那么交换一次即可 - 有
放反(如 ),那么交换两次即可 - 有
放反(如 ),那么交换三次即可
贪心的思想肯定是先将所有的情况一放好,然后是二和三。
每个数应该放在哪里我们是知道的,所以枚举一下就好了
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> // using namespace __gnu_pbds; // using namespace __gnu_cxx; using namespace std; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) #ifdef LOCAL FILE *InFile = infile("in.in"),*OutFile = outfile("out.out"); // FILE *ErrFile=errfile("err.err"); #else FILE *Infile = stdin,*OutFile = stdout; //FILE *ErrFile = stderr; #endif using ll=long long;using ull=unsigned long long; using db = double;using ldb = long double; const int N = 2e5 + 10; int n,a[N],num[5],L[5],R[5],have[5][5],ans = 0; vector<int> pos[5]; inline void solve(){ cin>>n; for(int i = 1;i <= n; ++i) cin>>a[i],num[a[i]]++,pos[a[i]].push_back(i); for(int i = 1;i <= 4; ++i) L[i] = R[i-1]+1,R[i] = L[i] + num[i]-1; for(int i = 1;i <= 4; ++i){ for(int j = L[i];j <= R[i]; ++j){ have[a[j]][i]++; } } for(int i = 1;i <= 4; ++i){ for(int j = 1;j <= 4; ++j){ if(i == j) continue; int k = min(have[i][j],have[j][i]); ans += k; have[i][j] -= k; have[j][i] -= k; } } for(int i = 1;i <= 4; ++i){ for(int j = 1;j <= 4; ++j){ if(i == j) continue; for(int k = 1;k <= 4; ++k){ if(k == i || k == j) continue; int emm = min({have[j][i],have[k][j],have[i][k]}); ans += 2*emm; have[j][i] -= emm; have[k][j] -= emm; have[i][k] -= emm; } } } for(int i = 1;i <= 4; ++i){ for(int j = 1;j <= 4; ++j){ if(i == j) continue; for(int k = 1;k <= 4; ++k){ if(k == i || k == j) continue; for(int t = 1;t <= 4; ++t){ if(t == i || t == j || t == k) continue; int emm = min({have[j][i],have[k][j],have[t][k],have[i][t]}); ans += 3 * emm; have[j][i]-=emm; have[k][j]-=emm; have[t][k]-=emm; have[i][t]-=emm; } } } } cout<<ans; } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
T2 生活在hzoi上
不会做,放官方题解了
题面锅了,谢罪。
首先我们先考虑一个暴力。枚举第二棵树的形态求方案。
先给他转化一下,容易发现只在一棵树里出现的边是没用的,那么考虑两棵树内都存在的边。而根据定义,如果只保留两棵树内都存在的边,那同一联通块内的节点给的数是一样的。
那么设
然后考虑正解。现在答案是这个东西:
有个憨批式子叫子集反演:
那设个
其中
其中
那么代回原式:
先特判掉
考虑一下怎么算后边一堆东西。设个
考虑优化。我们
那么设
初值:
转移:
-
:两种情况,一种是和下边的儿子成为一个联通块,另一个是断开儿子的边(儿子的联通块必须选了标记点)。那么就是 。 -
:也是要么断开要么不断。断开必须儿子选了,不断必须儿子没选。那么就是 。
updata on 2024-08-11 17:39:06 星期日:
贺官方题解被jijidawangD了,于是把jijidawang的贺下来了
首先注意到对于这个限制实际上可以只考虑
考虑如果没有不能选原有的树边的限制就是一个
对于这个式子的解释就是钦定选
那么先提出来
T3 嘉然今天吃什么
[Ynoi Easy Round 2021] TEST_68
全场第二道可做题还是Ynoi的虽然是Easy Round
一开始以为是Dsu On Tree,结果糖了一场以后还是感觉不可做。
这道题勉强算是部分分启发正解(反正没有启发我)
异或最大,考虑
我们通过分析性质观察样例发现,很多点的答案都是全局最大值。
那么先将全局最大值处理出来,然后考虑异或后为最大值的两个点
发现只有根到这两个点的简单路径上的点的答案才有可能不是全局最大值。
从上往下暴力跳链,统计答案即可。
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> // using namespace __gnu_pbds; // using namespace __gnu_cxx; using namespace std; #define infile(x) freopen(x,"r",stdin) #define outfile(x) freopen(x,"w",stdout) #define errfile(x) freopen(x,"w",stderr) #ifdef LOCAL FILE *InFile = infile("in.in"),*OutFile = outfile("out.out"); // FILE *ErrFile=errfile("err.err"); #else FILE *Infile = stdin,*OutFile = stdout; //FILE *ErrFile = stderr; #endif using ll=long long;using ull=unsigned long long; using db = double;using ldb = long double; const int N = 5e5 + 10; class Trie{ private: int tree[N*60][3],ed[N*60],tot; public: inline void insert(ll x){ int p = 0; for(int i = 60; i >= 0; --i){ int k = (x>>i)&1; if(!tree[p][k]) tree[p][k] = ++tot; p = tree[p][k]; } } inline ll query(ll x){ int p = 0; ll sum = 0; for(int i = 60; i >= 0; --i){ int k = (x>>i)&1; if(tree[p][k^1]) sum += (1ll<<i),p = tree[p][k^1]; else p = tree[p][k]; } return sum; } inline void clear(){ memset(tree,0,sizeof tree); tot = 0; } }T; struct EDGE{int to,next;}edge[N<<1]; int head[N],cnt; inline void add(int u,int v){ edge[++cnt] = {v,head[u]}; head[u] = cnt; } int dfn[N],rdfn[N],tot,bg[N],ed[N]; int n,fa[N],x,y; void dfs(int x){ rdfn[dfn[x] = bg[x] = ++tot] = x; for(int i = head[x]; i;i = edge[i].next){ int y = edge[i].to; if(y == fa[x]) continue; dfs(y); } ed[x] = tot; } ll a[N],mx,ans[N],now; inline void solve(){ cin>>n; for(int i = 2;i <= n; ++i) cin>>fa[i],add(fa[i],i); for(int i = 1;i <= n; ++i) cin>>a[i],T.insert(a[i]); for(int i = 1;i <= n; ++i){ ll res = T.query(a[i]); if(res > mx) mx = res,x = i; } for(int i = 1;i <= n; ++i) if((a[x] ^ a[i]) == mx){y = i;break;} dfs(1); vector<int> p;memset(ans,-1,sizeof ans); int id = x;T.clear(); while(x) p.emplace_back(x),x = fa[x]; reverse(p.begin(),p.end()); for(int i = 0;i + 1 < p.size(); ++i){ int u = p[i],v = p[i + 1];ans[u] = now; T.insert(a[u]);now = max(now,T.query(a[u])); for(int j = head[u]; j;j = edge[j].next){ int t = edge[j].to; if(t == fa[u] || t == v) continue; for(int k = bg[t];k <= ed[t]; ++k){ T.insert(a[rdfn[k]]); now = max(now,T.query(a[rdfn[k]])); } } } ans[id] = now;now = 0,id = y;T.clear(); vector<int> ().swap(p); while(y) p.emplace_back(y),y = fa[y]; reverse(p.begin(),p.end()); for(int i = 0;i + 1 < p.size(); ++i){ int u = p[i],v = p[i + 1];ans[u] = now; T.insert(a[u]);now = max(now,T.query(a[u])); for(int j = head[u]; j;j = edge[j].next){ int t = edge[j].to; if(t == fa[u] || t == v) continue; for(int k = bg[t];k <= ed[t]; ++k){ T.insert(a[rdfn[k]]); now = max(now,T.query(a[rdfn[k]])); } } } ans[id] = now; for(int i = 1;i <= n; ++i) cout<<(ans[i] == -1?mx:ans[i])<<'\n'; } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
T4 APJifengc
不会,贺的官方题解。
负环想到差分约束。设第
设
对于边权为
边权为
假如我们知道
如果
设
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18353554
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】