Codeforces Round #809 (Div. 2)
2022/7/19 下午VP
传送门:https://codeforces.com/contest/1706
A. Another String Minimization Problem
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int a[N]; signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ int n,m;std::cin>>n>>m; for(int i=1;i<=n;i++)std::cin>>a[i]; std::string s;for(int i=1;i<=m;i++)s+='B'; for(int i=1;i<=n;i++){ int l = a[i]-1,r=m-a[i]; if(l>r)std::swap(l,r); if(s[l]=='A')s[r]='A'; else s[l]='A'; } std::cout<<s<<"\n"; } }
B. Making Towers
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int c[N]; int ans[N]; int last[N]; signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ int n;std::cin>>n; for(int i=1;i<=n;i++)ans[i]=0; for(int i=1;i<=n;i++)last[i]=0; for(int i=1;i<=n;i++)std::cin>>c[i]; for(int i=1;i<=n;i++){ if(last[c[i]]==0||(i-last[c[i]])%2==1){ ans[c[i]]++; last[c[i]]=i; } } for(int i=1;i<=n;i++)std::cout<<ans[i]<<" \n"[i==n]; } }
C. Qpwoeirut And The City
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int h[N]; int dp[N][2]; signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ int n;std::cin>>n; dp[0][1]=dp[0][0]=dp[1][0]=dp[1][1]=0; for(int i=2;i<=n;i++)dp[i][0]=dp[i][1]=1e17; for(int i=1;i<=n;i++)std::cin>>h[i]; for(int i=2;i<=n;i++){ dp[i][0]=dp[i-2][0]+std::max(0ll,std::max(h[i-1],h[i+1])-h[i]+1); if(i!=2)dp[i][1]=std::min(dp[i-2][1],dp[i-3][0])+std::max(0ll,std::max(h[i-1],h[i+1])-h[i]+1); } if(n&1)std::cout<<dp[n-1][0]<<"\n"; else std::cout<<std::min({std::min(dp[n-1][0],dp[n-1][1]),dp[n-2][0]})<<"\n"; } }
D1. Chopping Carrots (Easy Version)
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int a[N];int n,k; int check(int p){ int maxs=1; for(int i=1;i<=n;i++){ int ma=1e17; for(int j=1;j<=k;j++){ if(a[i]/j>=p){ ma=std::min(ma,a[i]/j); } else break; } maxs=std::max(maxs,ma); } return maxs-p; } signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ std::cin>>n>>k; for(int i=1;i<=n;i++){ std::cin>>a[i]; } int ans=1e17; for(int mins=0;mins<=a[1];mins++){ ans=std::min(ans,check(mins)); } std::cout<<ans<<"\n"; } }
D2. Chopping Carrots (Hard Version)
整除分块
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int a[N];int n,k; int ans[N];//以i为最小值的max void init(){//整除分块 for(int i=0;i<N;i++)ans[i]=i; int last=1e17; for(int i=1;i<=n;i++){ for(int l=1,r;l<=std::min(a[i],k);l=r+1){ r=a[i]/(a[i]/l); int v=a[i]/l; ans[v+1]=std::max(ans[v+1],last); last=v; } ans[0]=std::max(ans[0],last); } for(int i=1;i<=a[1];i++)ans[i]=std::max(ans[i],ans[i-1]); } signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ std::cin>>n>>k; for(int i=1;i<=n;i++)std::cin>>a[i]; init(); int anss=1e17; for(int i=0;i<=a[1];i++){ anss=std::min(ans[i]-i,anss); } std::cout<<anss<<"\n"; } }
E. Qpwoeirut and Vertices
题意:t组输入。每组由n个顶点,m条边的连通无向图,q次询问。
每次询问一个区间l,r。求使得[l,r]的所有顶点互相可达的最小的k。k是选取的[1,k]条边。
解法1(最小生成树,LCA,st表):
参考yaqu姐姐的代码参悟的:https://codeforces.com/contest/1706/submission/164890534
问题转化为:一颗权值为边的编号的最小生成树,找到[1,k]两两可达的所有边的最大边权。
在树上找两点间路径的最大边权,就是在找最近公共祖先的路上顺便记录最大值。用倍增实现即可。
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int fa[N];int n,m,q; int st[N][30];//点间最大值st表 int father[N][30],maxst[N][30];//父节点倍增,边权倍增 int dep[N];//深度 struct Edge{ int from,to,k;//两个端点,权值。 }; std::vector<Edge>edge;//边集 std::vector<std::pair<int,int>>to[N]; void clear(){ edge.clear(); for(int i=0;i<=n;i++)fa[i]=i; for(int i=0;i<=n;i++)to[i].clear(); for(int i=0;i<=n;i++){for(int j=0;j<30;j++)maxst[i][j]=st[i][j]=father[i][j]=0;} for(int i=0;i<=n;i++)dep[i]=0; } int find(int x) {return fa[x] == x ? x :fa[x]=find(fa[x]);} //并查集路径压缩 void Kruskal(){//最小生成树 for(Edge i:edge){ int x=find(i.from); int y=find(i.to); if(x==y)continue; fa[x]=y; to[x].push_back({y,i.k});to[y].push_back({x,i.k}); } } int lca(int x,int y){ int ans=0; if(dep[x]>dep[y])std::swap(x,y); if (dep[y] > dep[x])std::swap(x, y); for (int i = 20; i >= 0; i--) { if (father[x][i] && dep[father[x][i]] >= dep[y]){ ans=std::max(ans,maxst[x][i]); x = father[x][i]; } } if(x==y)return ans; for(int i=20;i>=0;i--){ if(father[x][i]!=father[y][i]){ ans=std::max(ans,std::max(maxst[x][i],maxst[y][i])); x=father[x][i]; y=father[y][i]; } } return ans=std::max(ans,std::max(maxst[x][0],maxst[y][0])); } void dfs(int son,int last){ father[son][0]=last; dep[son]=dep[last]+1; for(auto k:to[son]){ if(k.first!=last){ maxst[k.first][0]=maxst[k.first][1]=k.second; dfs(k.first,son); } } } void init(){ Kruskal();//建树 int root=find(1);//最小生成树的树根 dfs(root,0);//找到根,开始dfs for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)father[j][i]=father[father[j][i-1]][i-1]; for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)maxst[j][i]=std::max(maxst[father[j][i-1]][i-1],maxst[j][i-1]); for(int i=1;i<n; i++) {st[i][0]=lca(i,i+1);} for (int i=1;i<=20;i++) { for (int j=1;j+(1ll<<i)-1<=n;j++) { st[j][i]=std::max(st[j][i-1],st[j+(1<<(i-1))][i-1]); } } } int query(int l,int r){ int x=log2(r-l+1); return std::max(st[l][x],st[r-(1<<x)+1][x]); } int slove(int l,int r){ int ans=0; if(l==r)return 0; if(l==r-1)return st[l][0]; return query(l,r-1); } signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ std::cin>>n>>m>>q; std::vector<int>ans; clear(); for(int i=0;i<m;i++){ int a,b;std::cin>>a>>b; edge.push_back({a,b,i+1}); } init(); while(q--){ int l,r;std::cin>>l>>r; ans.push_back(slove(l,r)); } for(int i=0;i<ans.size();i++)std::cout<<ans[i]<<" \n"[i==ans.size()-1]; } }
解法2(启发式合并+st表):
#include <bits/stdc++.h> #define int long long const int N = 1e5 + 10; int n,m,q; int fa[N],st[N][20]; std::vector<int>to[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} //并查集路径压缩 void clear(){ for(int i=0;i<=n;i++)fa[i]=i; for(int i=0;i<=n;i++){ to[i].clear(); to[i].push_back(i); } } int query(int l,int r){//st表查询 int k=log2(r-l+1); return std::max(st[l][k],st[r-(1<< k)+1][k]); } int slove(int l,int r){ if(l==r)return 0; return query(l,r-1); } void merge(int x,int y,int k){//把小的点集合并到大的上面。 if(to[x].size()>to[y].size())std::swap(x,y); for(int i:to[x]){ if(find(i+1)==y)st[i][0]=k;//找小点集在大点集里是否有相邻点。 if(find(i-1)==y)st[i-1][0]=k; to[y].push_back(i); } fa[x]=y;//合并 } signed main() { std::ios::sync_with_stdio(false); int t;std::cin>>t; while(t--){ std::cin>>n>>m>>q; std::vector<int>ans; clear(); for(int i=1;i<=m;i++){ int a,b;std::cin>>a>>b; int x=find(a);int y=find(b); if(x==y)continue; merge(x,y,i); } for (int j = 1; j <= 20; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i ++) { st[i][j] = std::max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); } } while(q--){ int l,r;std::cin>>l>>r; ans.push_back(slove(l,r)); } for(int i=0;i<ans.size();i++)std::cout<<ans[i]<<" \n"[i==ans.size()-1]; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!