AtCoder Beginner Contest 361
ABC361 A - Insert
代码(签到题)
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int n,m,x,a[111];
int main(){
cin>>n>>m>>x;
for (int i=1;i<=n;++i) cin>>a[i];
for (int i=1;i<=m;++i) cout<<a[i]<<' ';
cout<<x<<' ';
for (int i=m+1;i<=n;++i) cout<<a[i]<<' ';
return 0;
}
ABC361 B - Intersection of Cuboids
分析
没想到这场竟然 B 题被卡了很久,实际上相交的话那么左下角坐标分别的最大值和右上角坐标分别的最小值可以构成交集长方体,
用这个长方体的八个角所在的小正方体判断是否同时存在两个长方体中。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
int a[6],b[6],c[6];
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool check(int lx,int ly,int lz,int rx,int ry,int rz){
if (lx>=rx||ly>=ry||lz>=rz) return 0;
if (a[0]<=lx&&rx<=a[3]&&a[1]<=ly&&ry<=a[4]&&a[2]<=lz&&rz<=a[5]){
if (b[0]<=lx&&rx<=b[3]&&b[1]<=ly&&ry<=b[4]&&b[2]<=lz&&rz<=b[5]) return 1;
return 0;
}
return 0;
}
int main(){
for (int i=0;i<6;++i) a[i]=iut();
for (int i=0;i<6;++i) b[i]=iut();
for (int i=0;i<3;++i) c[i]=max(a[i],b[i]);
for (int i=4;i<6;++i) c[i]=min(a[i],b[i]);
for (int i=0;i<2;++i)
for (int j=0;j<2;++j)
for (int k=0;k<2;++k)
if (check(c[0+i*3]-i,c[1+j*3]-j,c[2+k*3]-k,c[0+i*3]+(i^1),c[1+j*3]+(j^1),c[2+k*3]+(k^1)))
return !printf("Yes");
return !printf("No");
}
ABC361 C - Make Them Narrow
代码(这才是真的签到题,上一题啥玩意啊)
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
int n,k,a[200011],ans=0x3f3f3f3f;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
int main(){
n=iut(),k=n-iut();
for (int i=1;i<=n;++i) a[i]=iut();
sort(a+1,a+1+n);
for (int i=1;i+k-1<=n;++i) ans=min(ans,a[i+k-1]-a[i]);
return !printf("%d",ans);
}
ABC361 D - Go Stone Puzzle
分析
实际上就是广搜求最短路,不过位运算有点麻烦而已
代码
// LUOGU_RID: 172720686
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
string strS,strT;
queue<pair<int,int> >q;
int dp[65535][16],n,S,T,b[16];
int main(){
cin>>n>>strS>>strT;
for (int i=0;i<(1<<n);++i)
for (int j=0;j<=n;++j) dp[i][j]=-1;
for (int i=0;i<n;++i)
if (strS[i]=='B') S=S<<1|1;
else S=S<<1;
for (int i=0;i<n;++i)
if (strT[i]=='B') T=T<<1|1;
else T=T<<1;
dp[S][n]=0,q.push(make_pair(S,n));
while (!q.empty()){
pair<int,int>t=q.front(); q.pop();
int now=t.first,x=t.second;
if (now==T&&x==n) break;
for (int i=0;i<n;++i) b[i+(i>=x)*2]=(now>>(n-i-1))&1;
for (int i=0,t;i<x-1;++i){
swap(b[x],b[i]),swap(b[x+1],b[i+1]),t=0;
for (int j=0;j<i;++j) t=t<<1|b[j];
for (int j=i+2;j<n+2;++j) t=t<<1|b[j];
if (dp[t][i]==-1){
dp[t][i]=dp[now][x]+1;
q.push(make_pair(t,i));
}
swap(b[x],b[i]),swap(b[x+1],b[i+1]);
}
for (int i=x+2,t;i<=n;++i){
swap(b[x],b[i]),swap(b[x+1],b[i+1]),t=0;
for (int j=0;j<i;++j) t=t<<1|b[j];
for (int j=i+2;j<n+2;++j) t=t<<1|b[j];
if (dp[t][i]==-1){
dp[t][i]=dp[now][x]+1;
q.push(make_pair(t,i));
}
swap(b[x],b[i]),swap(b[x+1],b[i+1]);
}
}
return !printf("%d",dp[T][n]);
}
ABC361 E - Tree and Hamilton Path 2
分析
如果还要回到起点的话遍历的顺序按欧拉序每条边都会正好经过两遍,
所以求最短距离也就是边权和两倍再减去树的直径
代码
#include <iostream>
using namespace std;
const int N=200011;
struct node{int y,w,next;}e[N<<1];
long long ans,dp[N],sum;
int as[N],n,et=1;
void dfs(int x,int fa){
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa){
dfs(e[i].y,x);
ans=max(ans,dp[x]+dp[e[i].y]+e[i].w);
dp[x]=max(dp[x],dp[e[i].y]+e[i].w);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1,x,y,w;i<n;++i){
cin>>x>>y>>w,sum+=w*2;
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
dfs(1,0);
cout<<sum-ans;
return 0;
}
ABC361 F - x = a^b
分析
考虑立方或者幂次更高的数已经很少了,不妨特判平方的情况,剩下的数直接枚举并去重即可
代码
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
unordered_map<long long,bool>v;
long long n,ans;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,ans=sqrt((long double)n);
for (int i=3;i<=61;i+=2){
for (long double j=2;;++j)
if (pow(j,i)<=n){
long long t=pow(j,i);
if (sqrt(t)!=floor(sqrt(t))&&!v[t]){
v[t]=1,++ans;
}
}else break;
}
cout<<ans;
return 0;
}
ABC361 G - Go Territory
分析
将四连通格点个数转化为连通块大小后,不妨按横坐标拆分成列状的连通块,
然后用并查集进行合并连边,由于连边的数目可能很多,可以采用双指针交叉连边。
注意网格是无界的所以最外一圈要留出来。
代码
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int N=200003;
vector<int>G[N]; map<pair<int,int>,int>uk;
int f[N<<2],n,m; long long ans,siz[N<<2];
int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
void merge(int x,int y){
int u=getf(x),v=getf(y);
if (u<v) u^=v,v^=u,u^=v;
if (u>v) f[u]=v,siz[v]+=siz[u];
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,ans=1ll*N*N-n;
for (int i=-1;i<N-1;++i){
G[i+1].push_back(-2);
G[i+1].push_back(N-1);
}
for (int i=1;i<=n;++i){
int x,y;
cin>>x>>y;
G[x+1].push_back(y);
}
m=uk[make_pair(0,0)]=f[1]=1,siz[1]=N;
for (int i=0;i<N-1;++i){
sort(G[i+1].begin(),G[i+1].end());
int l=G[i+1].size(),L=G[i].size(),I=0,J=0;
for (int j=0;j<l-1;++j){
uk[make_pair(i+1,j)]=++m,f[m]=m;
siz[m]=G[i+1][j+1]-G[i+1][j]-1;
}
while (I<L-1&&J<l-1){
if (max(G[i][I],G[i+1][J])+1<=min(G[i][I+1],G[i+1][J+1])-1)
merge(uk[make_pair(i,I)],uk[make_pair(i+1,J)]);
if (G[i][I+1]>G[i+1][J+1]) ++J;
else if (G[i][I+1]<G[i+1][J+1]) ++I;
else ++I,++J;
}
}
cout<<ans-siz[1];
return 0;
}