暑假集训csp提高模拟21
赛时rank 47,T1 20,T2 0,T3 30,T4 45
赛时最后想到了T1的正解,可惜没有打出来。
整场比赛都在死磕T1的神秘构造,导致本来可以AC的T2没有写,开题的策略不行,太容易死磕了。
T1 黎明与萤火
贪心构造。
先给一组数据
Input: 5 0 1 2 3 4 Output: YES 2 4 1 3 5
通过这组数据可以发现,从叶子节点点往上找可以删去的删去是符合条件的。
考虑证明为什么。
根据题意,当
那么就考虑到,对于每一颗子树,只有当它的大小为奇数时,才可以删去。
假设有一个节点
如果它的所有子树都为奇数,那么只有它有奇数颗子树时,这颗子树才合法。
所以
所以就从深度大的往深度小的搜索即可
点此查看代码
#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; 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 n,d[N],fa[N]; stack<int> s; vector<int> ans; bitset<N> vis; void dfs1(int x,int f){ fa[x] = f;s.push(x); for(int i = head[x]; i;i = edge[i].next){ int y = edge[i].to; if(y == f) continue; dfs1(y,x); } } void dfs2(int x){ vis[x] = true; ans.emplace_back(x); for(int i = head[x]; i;i = edge[i].next){ int y = edge[i].to;d[y]--; if(y == fa[x] || vis[y]) continue; if(d[y] % 2 == 0) dfs2(y); } } inline void solve(){ cin>>n; for(int i = 1,fa;i <= n; ++i){ cin>>fa; if(!fa) continue; add(i,fa);add(fa,i); d[i]++,d[fa]++; } dfs1(1,0); while(s.size()){ int x = s.top();s.pop(); if(d[x] % 2 == 0) dfs2(x); } if(ans.size() == n){ cout<<"YES\n"; for(auto i : ans) cout<<i<<'\n'; } else cout<<"NO\n"; } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
T2 Darling Dance
简单题。
建出以1为根的最短路树,bfs保留即可。
点此查看代码
#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 = 3e5 + 10; int n,m,k; struct EDGE{int to,next,w;}edge[N<<1]; int head[N],cnt; inline void add(int u,int v,int w){ edge[++cnt] = {v,head[u],w}; head[u] = cnt; } int u[N],v[N],w[N],fa1[N],fa2[N]; #define pii pair<int,int> #define mk make_pair bitset<N> vis; ll dist[N]; inline void dijkstra(int s){ vis.reset(); memset(dist,0x3f,sizeof dist); priority_queue<pii,vector<pii>,greater<pii> > q; dist[s] = 0; q.push(mk(0,s)); while(q.size()){ int x = q.top().second;q.pop(); if(vis[x]) continue; vis[x] = true; for(int i = head[x]; i;i = edge[i].next){ int y = edge[i].to; if(dist[y] > dist[x] + edge[i].w){ dist[y] = dist[x] + edge[i].w; fa1[y] = x; fa2[y] = i; q.push(mk(dist[y],y)); } } } } vector<int> son[N]; inline void solve(){ cin>>n>>m>>k; for(int i = 1,u,v,w;i <= m; ++i){ cin>>u>>v>>w; add(u,v,w),add(v,u,w); } dijkstra(1); for(int i = 2;i <= n; ++i) son[fa1[i]].emplace_back(i); vector<int> ans; queue<int> q; q.push(1); while(q.size() && ans.size() <= k){ int x = q.front();q.pop(); for(auto y : son[x]){ if(ans.size() == k)break; ans.push_back((int)(ceil(fa2[y]/2.0))); q.push(y); } } cout<<ans.size()<<'\n'; for(auto i : ans) cout<<i<<' '; } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
T3 Non-breath oblige
将线段树维护值转化为维护时间戳。
将询问离线,既然询问是查询
卡卡常就过了。
线段树变成珂朵莉树也可以。
点此查看代码
#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; #define getchar getchar_unlocked #define putchar putchar_unlocked template<class T> inline void read(T &x){ x = 0; char s = getchar(); for(;s < '0' || '9' < s;s = getchar()); for(;'0' <= s && s <= '9';s = getchar()) x = (x<<1) + (x<<3) + (s^48); } template<class T> void write1(T x){ if(x > 9) write1(x/10); putchar(x%10 + '0'); } template<class T> inline void write(T x){ if(x < 0) x = -x,putchar('-'); write1(x); } const int N = 1e6 + 10; int n,m,q; struct node{ int op,l,r,x; }a[N]; class Segment_Tree{ private: struct segment_tree{ int l,r,val,lazy; #define l(k) tree[k].l #define r(k) tree[k].r #define val(k) tree[k].val #define lazy(k) tree[k].lazy }tree[N<<2]; inline void pushdown(int k){ if(lazy(k)){ val(k<<1) = val(k<<1|1) = lazy(k); lazy(k<<1) = lazy(k<<1|1) = lazy(k); lazy(k) = 0; } } public: void build(int k,int l,int r){ l(k) = l,r(k) = r;val(k) = lazy(k) = 0; if(l == r) return val(k) = 0,void(); int mid = (l + r) >> 1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void update(int k,int l,int r,int val){ if(l <= l(k) && r(k) <= r) return val(k) = lazy(k) = val,void(); pushdown(k); int mid = (l(k) + r(k)) >> 1; if(l <= mid) update(k<<1,l,r,val); if(r > mid) update(k<<1|1,l,r,val); } int query(int k,int pos){ if(l(k) == r(k)) return val(k); pushdown(k); int mid = (l(k) + r(k)) >> 1; if(pos <= mid) return query(k<<1,pos); else return query(k<<1|1,pos); } }T; vector<pair<int,int> > que[N]; class BIT{ private: ll tree[N]; #define lowbit(x) (x&(-x)) public: int mx; inline void update(int pos,int val){ if(!pos) return; for(int i = pos;i <= mx;i += lowbit(i)) tree[i] += val; } inline ll query(int pos){ ll res = 0; for(int i = pos; i;i -= lowbit(i)) res += tree[i]; return res; } }Tr; ll ans[N]; inline void solve(){ read(n),read(m),read(q); T.build(1,1,n); Tr.mx = m; int tot = 0; for(int i = 1;i <= m; ++i){ read(a[i].op); if(a[i].op == 2){ tot++; read(a[i].l),read(a[i].r),read(a[i].x); T.update(1,a[i].l,a[i].r,i); } if(a[i].op == 1){ read(a[i].l),read(a[i].r); int res1 = T.query(1,a[i].l); int res2 = T.query(1,a[i].r); T.update(1,a[i].l,a[i].l,res2); T.update(1,a[i].r,a[i].r,res1); } if(a[i].op == 3) read(a[i].x),a[i].r = T.query(1,a[i].x); } for(int i = 1,l,r;i <= q; ++i){ read(l),read(r); que[r].emplace_back(make_pair(l-1,i)); } for(int i = 1;i <= m; ++i){ if(a[i].op == 3) Tr.update(a[i].r,a[a[i].r].x); for(auto j : que[i]) ans[j.second] = Tr.query(i) - Tr.query(j.first); } for(int i = 1;i <= q; ++i) write(ans[i]),putchar('\n'); } signed main(){ cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
T4 妄想感伤代偿联盟
正解好像很唐,不会。
挂一下。
打了一个记忆化加上一个数据点分治。
比某些人的正解快
点此查看代码
#include<bits/stdc++.h> #include<bits/extc++.h> using namespace std; using ll = long long; const int N = 6e5 + 10; const ll base = 2333,mod = 1e9 + 3579; string s[N]; int n,m,len[N]; vector<ll > H[N]; vector<ll > h[N]; ll pw[N]; unordered_map<int,int> mp[N]; int Ans[5000][5000],to[N]; inline void solve(){ pw[0] = 1; for(int i = 1;i < N;++i) pw[i] = pw[i - 1] * base % mod; cin>>n>>m; for(int i = 1;i <= n; ++i){ cin>>s[i]; len[i] = s[i].length(); } vector<int> big;big.clear(); for(int i = 1;i <= n; ++i){ H[i].push_back(0); for(int j=0;j<len[i];j++){ H[i].push_back((H[i].back()*base%mod+s[i][j]-'a'+1)%mod); } h[i].push_back(0); for(int j=len[i]-1,k=0;j>=0;j--,k++){ h[i].push_back((h[i].back()+(s[i][j]-'a'+1)*pw[k]%mod)%mod); } if(len[i] > 1000) big.emplace_back(i),to[i] = big.size()-1; // for(auto j:H[i]) cout<<j<<' '; // cout<<'\n'; // for(auto j:h[i]) cout<<j<<' '; // cout<<"\n\n"; } int x,y; int siz = big.size(); for(int i = 0;i < siz; ++i){ for(int j = 0;j < siz; ++j){ if(i == j) continue; int x = big[i],y = big[j]; int l = 0,r = min(len[x],len[y]),ans = 0; for(int mid = r;mid >= l; --mid){ if(h[x][mid] == H[y][mid]){ ans = mid;break; } } Ans[i][j] = ans; } } while(m--){ cin>>x>>y; if(x > n || y > n){cout<<"0\n";continue;} if(x == y){cout<<len[x]<<'\n';continue;} int l = 0,r = min(len[x],len[y]),ans = 0; if(r > 1000){ cout<<Ans[to[x]][to[y]]<<'\n'; continue; } if(mp[x].find(y) != mp[x].end()){ cout<<mp[x][y]<<'\n'; continue; } if(min(len[x],len[y])<=1000){ for(int i=min(len[x],len[y]);i>=0;i--){ if(h[x][i]==H[y][i]){ ans = i; break; } } } cout<<(mp[x][y] = ans)<<'\n'; } } signed main(){ #ifdef LOCAL freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif cin.tie(nullptr)->sync_with_stdio(false); cout.tie(nullptr)->sync_with_stdio(false); solve(); }
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18361807
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!