[题解] AtCoder Beginner Contest 409(ABC409) A~F
A - Conflict
输出Yes\(\iff\)存在\(t[i]\)和\(a[i]\)同时为o。
时间复杂度\(O(1)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
string t,a;
bool check(){
for(int i=0;i<n;i++) if(t[i]=='o'&&a[i]=='o') return 1;
return 0;
}
signed main(){
cin>>n>>t>>a;
cout<<(check()?"Yes\n":"No\n");
return 0;
}
B - Citation
显然答案\(\in[0,n]\),枚举验证即可。时间复杂度\(O(n^2)\)。
点击查看代码
#include<bits/stdc++.h>
#define N 105
using namespace std;
int n,a[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=n;~i;i--){
int cnt=0;
for(int j=1;j<=n;j++){
cnt+=(a[j]>=i);
}
if(cnt>=i) cout<<i,exit(0);
}
return 0;
}
发现答案有单调性,也可以二分做到\(O(n\log n)\)。
C - Equilateral Triangle
首先\(L\bmod 3\neq 0\)的话直接输出No。
然后用一个桶数组记录下每个位置的点数量,然后遍历形如\((i,i+\frac{L}{3},i+\frac{2L}{3})\)的三元组统计答案即可。
时间复杂度\(O(n+L)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 300010
using namespace std;
int n,l,d,cur,t[N],ans;
signed main(){
cin>>n>>l,t[0]=1;
for(int i=1;i<n;i++) cin>>d,(cur+=d)%=l,t[cur]++;
if(l%3) cout<<0,exit(0);
for(int i=0;i<l/3;i++)
ans+=t[i]*t[i+l/3]*t[i+l/3*2];
cout<<ans<<"\n";
return 0;
}
D - String Rotation
显然可以贪心。找到最小的\(i\)使得\(s[i]>s[i+1]\),然后将\(s[i]\)取出,放在最小的\(j\)使得\(s[j]>s[i]\)之前。
若找不到这样的\(j\)就把\(s[i]\)放在最后面;若找不到这样的\(i\)则直接原样输出。
时间复杂度\(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s;
signed main(){
cin>>t;
while(t--){
cin>>n>>s;
bool f=0;
for(int i=0;i<n-1;i++){
if(s[i]>s[i+1]){
for(int j=0;j<i;j++) cout<<s[j];
bool flg=0;
for(int j=i+1;j<n;j++){
if(!flg&&s[j]>s[i]) flg=1,cout<<s[i];
cout<<s[j];
}
if(!flg) cout<<s[i];
cout<<"\n";
f=1;
break;
}
}
if(!f) cout<<s<<"\n";
}
return 0;
}
E - Pair Annihilation
单独考虑一条边对答案的贡献,任何一条边\((u,v,w)\)连接的\(2\)个部分的总和\(S\)和\(S'\)一定互为相反数,对答案至少有\(|S|*w\)的贡献。
因此只要电荷的移动不走回头路,就不存在冗余操作,答案就是最优的。
我们可以从叶节点开始逐层向上转移,转移的途中统计答案,到根节点就算结束,类似拓扑排序。
时间复杂度\(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
#define N 100010
#define int long long
using namespace std;
int n,x[N],deg[N],ans;
struct edge{int to,w;};
vector<edge> G[N];
queue<int> q;
void add(int u,int v,int w){G[u].emplace_back(edge{v,w}),deg[u]++;}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>x[i];
for(int i=1,u,v,w;i<n;i++) cin>>u>>v>>w,add(u,v,w),add(v,u,w);
for(int i=1;i<=n;i++) if(deg[i]==1) q.push(i);
while(!q.empty()){
int u=q.front();
q.pop();
for(auto i:G[u]){
int v=i.to,w=i.w;
if(!deg[v]) continue;
deg[u]--,deg[v]--;
ans+=abs(x[u])*w,x[v]+=x[u];
if(deg[v]==1) q.push(v);
}
}
cout<<ans<<"\n";
return 0;
}
F - Connecting Points
用并查集来维护连通性,并使用优先队列来选择距离最小的点对。
- 对于操作\(1\),遍历之前所有的点\(v\),把它们和新点\(u\)的距离\(d\)以\((u,v,d)\)的形式扔进优先队列。
- 对于操作\(2\),从队列中取出第一个\((u,v,d)\)使得\(u,v\)不在同一个连通块中。
- 若找不到,则输出
-1。 - 若能找到,则继续在队列中找所有\((u',v',d)\),将\(u'\)和\(v'\)在并查集上合并。
- 若找不到,则输出
- 对于操作\(3\),看看\(u,v\)是否处于并查集的同一集合中即可。
时间复杂度\(O((n+q)^2\log (n+q)^2)=O((n+q)^2\log (n+q))\)。
点击查看代码
#include<bits/stdc++.h>
#define N 1505
#define Q 1505
#define int long long
using namespace std;
struct Node{
int d,u,v;
bool operator < (const Node&x) const{return x.d<d;}
};
priority_queue<Node> q;
int n,tq,x[N+Q],y[N+Q],idx,fa[N+Q];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int dis(int i,int j){return abs(x[i]-x[j])+abs(y[i]-y[j]);}
void ins(int _x,int _y){
x[++idx]=_x,y[idx]=_y,fa[idx]=idx;
for(int i=1;i<idx;i++) q.push({dis(i,idx),i,idx});
}
signed main(){
cin>>n>>tq;
for(int i=1,x,y;i<=n;i++) cin>>x>>y,ins(x,y);
while(tq--){
int op,a,b;
cin>>op;
if(op==1){
cin>>a>>b;
ins(a,b);
}else if(op==2){
int k=-1;
while(!q.empty()){
Node t=q.top();
if((~k)&&k!=t.d) break;
q.pop();
if(find(t.u)==find(t.v)) continue;
if(k==-1) k=t.d;
if(k!=t.d) continue;
else fa[find(t.u)]=find(t.v);
}
cout<<k<<"\n";
}else{
cin>>a>>b;
cout<<(find(a)==find(b)?"Yes\n":"No\n");
}
}
return 0;
}
浙公网安备 33010602011771号