[题解]AtCoder Beginner Contest 416(ABC416) A~E
补题中~
A - Vacation Validation
枚举判定。
时间复杂度\(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
int n,l,r;
bool solve(){
for(int i=l;i<=r;i++) if(s[i]=='x') return 0;
return 1;
}
signed main(){
cin>>n>>l>>r>>s;
s=' '+s;
cout<<(solve()?"Yes\n":"No\n");
return 0;
}
B - 1D Akari
策略就是对于每一个.的连续段,选且仅选取其中一位置为o。
时间复杂度\(O(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
bool v=1;
signed main(){
cin>>s;
for(char i:s){
if(i=='.'){
if(v) cout<<"o",v=0;
else cout<<".";
}else{
cout<<"#";
v=1;
}
}
return 0;
}
C - Concat (X-th)
暴力枚举\(K^N\)种选择,然后nth_element或者排序来求第\(x\)小。
时间复杂度\(O(K^N\times N)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k,x,idx,a[15];
string s[15],t[100010];
void dfs(int pos){
if(pos>k){
idx++;
for(int i=1;i<=k;i++) t[idx]+=s[a[i]];
return;
}
for(int i=0;i<n;i++){
a[pos]=i;
dfs(pos+1);
}
}
signed main(){
cin>>n>>k>>x;
for(int i=0;i<n;i++) cin>>s[i];
dfs(1);
sort(t+1,t+1+idx);
cout<<t[x]<<"\n";
return 0;
}
D - Match, Mod, Minimize 2
据题意,\(A_i,B_i<M\)。
所以对于我们重排的序列,如果记答案初始为\(\sum\limits_{i=1}^n A_i+B_i\),那么如果\(A_i+B_i\ge M\)则额外产生\(-M\)的贡献,否则不产生贡献。
所以我们是要让\(A_i+B_i\ge M\)的数量尽可能多。
因此我们将\(A,B\)排序,两个指针\(p_1,p_2\)分别指向\(A\)的最小值、\(B\)的最大值,匹配成功则都移动,并答案\(-M\),否则仅\(p_1\)移动。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
int t,n,m,a[N],b[N];
signed main(){
cin>>t;
while(t--){
cin>>n>>m;
int ans=0;
for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i];
for(int i=1;i<=n;i++) cin>>b[i],ans+=b[i];
sort(a+1,a+1+n),sort(b+1,b+1+n);
for(int i=1,j=n;i<=n;i++)
if(a[i]+b[j]>=m) ans-=m,j--;
cout<<ans<<"\n";
}
return 0;
}
E - Development
看到\(n\)的范围,想到使用Floyd求解,\(f[i][j]\)为\(i,j\)间的最短时间。
询问操作直接对着\(f[][]\)统计就行了。
加边操作也很好实现,每次加边\(O(n^2)\)地利用这条边重新松弛一遍即可。
再考虑建机场的操作。首先想到每建一个机场就和其他机场之间连一条权值为\(T\)的边,然后依次松弛。然而这样是\(O(n^3)\)的,无法接受。
但是这道题有一个很好的特性,就是机场之间构成了一个团(完全子图),意味着任意两个机场之间可以自由来往。所以两点之间的最短路,最多只能坐一次飞机。因为多次飞机一定可以用一次飞机上位替代。
因此我们重新定义\(f\)为不坐飞机的最短路,用\(g[i]\)表示离\(i\)最近的机场的距离,输出\((i,j)\)的答案时,和\(g[i]+g[j]+T\)取一次\(\min\)即可。
时间复杂度\(O(n^3+n^2q)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=501;
int n,m,k,t,q,f[N][N],g[N];
bitset<N> is;
void ap(int u){//在u点建机场
is[u]=1;
for(int i=1;i<=n;i++){
g[i]=min(g[i],f[i][u]);
}
}
signed main(){
cin>>n>>m;
memset(f,0x3f,sizeof f),memset(g,0x3f,sizeof g);
for(int i=1,u,v,w;i<=m;i++){
cin>>u>>v>>w;
f[u][v]=f[v][u]=min(f[u][v],w);
}
for(int i=1;i<=n;i++) f[i][i]=0;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
}
}
cin>>k>>t;
for(int i=1,u;i<=k;i++) cin>>u,ap(u);
cin>>q;
int op,x,y,z;
while(q--){
cin>>op;
if(op==1){
cin>>x>>y>>z;
f[x][y]=f[y][x]=min(f[x][y],z);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=min({f[i][j],f[i][x]+f[y][j]+z,f[j][x]+f[y][i]+z});
if(is[j]) g[i]=min(g[i],f[i][j]);
}
}
}else if(op==2){
cin>>x;
ap(x);
}else{
int ans=0,s;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if((s=min(f[i][j],g[i]+g[j]+t))!=f[0][0]) ans+=s;
}
}
cout<<ans<<"\n";
}
}
return 0;
}
官方题解的思路是额外创建一个\(0\)号节点,任意机场到\(0\)号节点有一条权值为\(T\)的边,\(0\)号节点到任意机场有一条权值为\(0\)的边。这样建一个机场就相当于两次加边操作了。
浙公网安备 33010602011771号