牛客小白月賽29
A.進攻
https://ac.nowcoder.com/acm/contest/8564/A
題解:將戰機攻擊力從小到大排列,基地也如此。由於基地可以多次摧毀,線性掃描每個戰機能獲得的最大貢獻。
#include<bits/stdc++.h> using namespace std; const int N=1e6+100; int a[N]; int n,m; struct node { int x,y; bool operator <(const node &a)const{ if(x==a.x) return y<a.y;View Codereturn x<a.x; } }b[N]; int main() { cin>>n>>m; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) scanf("%d",&b[i].x); for(int i=1;i<=m;i++) scanf("%d",&b[i].y); sort(a+1,a+1+n); sort(b+1,b+1+m);long long ans=0; int j=1; int res=0; for(int i=1;i<=n;i++) { while(j<m&&a[i]>b[j].x) { res=max(res,b[j].y); j++; } ans+=res; } cout<<ans<<endl; }
B.二進位制
https://ac.nowcoder.com/acm/contest/8564/B
題解:二進位制每一位分開看
1.如果之前為0,現在為1;如果之前為1,現在為0.則該位可以通過異或操作得到。
2.如果之前為0,現在為1;如果之前為1,現在為1.則該位可以通過或操作得到。
3.如果之前為0,現在為0;如果之前為1,現在為0.則該位可以通過並0操作得到。
4.如果之前為0,現在為0;如果之前為1,現在為1.則不用操作。
因此可以用a=0,b=(1<<20)-1,分別代表每一位之前為0,每一位之前為1.然後觀察操作後的值的每一位。然後通過三個操作的值即可得到。
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; int a=0,b=(1<<20)-1; for(int i=0;i<n;i++) { int x,y; scanf("%d%d",&x,&y); if(x==1)a&=y,b&=y; else if(x==2)a|=y,b|=y; else a^=y,b^=y; } int or1=0,xor1=0,and1=(1<<20)-1; for(int i=19;i>=0;i--) { if(a>>i&1)//之前為0,現在為1 { if(b>>i&1)//之前為1,現在為1 or1+=1<<i; else//之前為1,現在為0 xor1+=1<<i; } else if(!(b>>i&1)) and1-=1<<i; } cout<<"3"<<endl; printf("1 %d\n",and1); printf("2 %d\n",or1); printf("3 %d\n",xor1); return 0; }View Code
C.積木
https://ac.nowcoder.com/acm/contest/8564/C
題解:對n*n*n方格塗黑白色,要求每個黑色相鄰的有兩個黑色,每個白色相鄰的有兩個白色的。
要求相同顏色的只有兩個相鄰的,因此只能由2*2*2的方案累積而成,當n為奇數時無解。當n為偶數時,則可以由若干個2*2*2的方案累計而成。
#include<bits/stdc++.h> using namespace std; const int N=110; int a[N][N][N]; int n; int main() { cin>>n; if(n%2) { puts("-1"); return 0; } a[1][1][1]=a[1][1][2]=1; a[1][2][1]=a[1][2][2]=0; for(int k=1;k<=n;k+=2) { for(int i=1;i<=n;i+=2) { for(int j=1;j<=n;j+=2) { int f; if(j==1&&i==1) f=!a[k-1][i][j]; else if(j==1) { f=a[k][i-2][j]; } else f=!a[k][i][j-2]; a[k][i][j]=a[k+1][i][j]=f; a[k][i][j+1]=a[k+1][i][j+1]=f; a[k][i+1][j]=a[k+1][i+1][j]=!f; a[k][i+1][j+1]=a[k+1][i+1][j+1]=!f; } } } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) printf("%d ",a[k][i][j]); puts(""); } puts(""); } return 0; }View Code
D.種樹
https://ac.nowcoder.com/acm/contest/8564/D
題解:對於這樣的樹,最多可以取m=(n/2+1)/2次max,貪心策略:由根結點到最大葉節點處取最大值。可以採用這樣的策略取得最大值:在深度小於等於採用最大值操作。
#include<bits/stdc++.h> using namespace std; const int N=5e5+100; int h[N],e[N],ne[N],w[N],idx; int tr[N]; int n,m; int dep[N]; void add(int a,int b) { ne[idx]=h[a]; e[idx]=b; h[a]=idx++; } void dfs(int u,int fa) { dep[u]=dep[fa]+1; for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(j==fa)continue; dfs(j,u); } } void dfs1(int u,int fa) { int l=0,r=0; for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(j==fa)continue; if(!l)l=j; else r=j; dfs1(j,u); } if(l) { if(dep[u]>m) tr[u]=min(tr[l],tr[r]); else tr[u]=max(tr[l],tr[r]); } else tr[u]=w[u]; } int main() { memset(h,-1,sizeof h); cin>>n; m=(n/2+1)/2; for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&b); if(a) { add(i,a); add(i,b); } } for(int i=1;i<=n;i++) scanf("%d",&w[i]); dfs(1,0); dfs1(1,0); cout<<tr[1]<<endl; return 0; }View Code
E.考試
https://ac.nowcoder.com/acm/contest/8564/E
簽到
#include<bits/stdc++.h> using namespace std; const int N=1010; int a[N]; int main() { int n,k; cin>>n>>k; for(int i=1;i<=n;i++) scanf("%d",&a[i]); int x; int ans=0; for(int i=1;i<=n;i++) { scanf("%d",&x); if(x!=a[i])ans++; } int res=n-ans; if(ans>k) res+=k; else res=n-(k-ans); cout<<min(n,res)<<endl; }View Code
F.項鍊
https://ac.nowcoder.com/acm/contest/8564/F
題解:直接採用雙鏈表模擬即可,對於翻轉操作,交換每個結點的左右結點值即可。
#include<bits/stdc++.h> using namespace std; const int N=1e4+1000; int l[N],r[N]; int n,m; int main() { cin>>n>>m; r[n]=1; l[1]=n; for(int i=2;i<=n;i++) { l[i]=i-1; r[i-1]=i; } for(int i=1;i<=m;i++) { int id,x,y; scanf("%d",&id); if(id==1) { scanf("%d%d",&x,&y); r[l[x]]=r[x]; l[r[x]]=l[x]; l[r[y]]=x; r[x]=r[y]; r[y]=x; l[x]=y; } else if(id==2) { scanf("%d%d",&x,&y); r[l[x]]=r[x]; l[r[x]]=l[x]; r[l[y]]=x; l[x]=l[y]; r[x]=y; l[y]=x; } else if(id==3) { for(int i=1;i<=n;i++) swap(l[i],r[i]); } else{ int cur=1; while(r[cur]!=1) { printf("%d ",cur); cur=r[cur]; } printf("%d\n",cur); } } return 0; }View Code
G.塗色
https://ac.nowcoder.com/acm/contest/8564/G
簽到
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; cout<<n+1<<endl; return 0; }View Code
H.圓
https://ac.nowcoder.com/acm/contest/8564/H
簽到
#include<bits/stdc++.h> using namespace std; int main() { int T; cin>>T; while(T--) { double x1,y1,r1,x2,y2,r2; cin>>x1>>y1>>r1>>x2>>y2>>r2; double ans=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); if((ans<=(r1+r2)&&ans>=abs(r1-r2))) puts("YES"); else puts("NO"); } return 0; }View Code
I.修改
https://ac.nowcoder.com/acm/contest/8564/I
題解:要使陣列所有數都變為0,即要使差分陣列都變為0.對於一個操作[l,r,w],可使差分陣列第l位變為0,因此,如果所有位置都能與第n+1位聯通,那麼就存在一些操作讓差分陣列都變成0。那麼如果將每個操作[l,r,w]視為一條邊,求最小生成樹即為最小解。
#include<bits/stdc++.h> using namespace std; const int N=2e5+100; struct node { int u,v,w; bool operator <(const node &a)const { return w<a.w; } }a[N]; int n,m; int p[N]; int find(int x) { if(p[x]!=x)p[x]=find(p[x]); return p[x]; } int main() { cin>>n>>m; for(int i=0;i<m;i++) { scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); } for(int i=1;i<=n;i++) p[i]=i; int cnt=0; long long ans=0; sort(a,a+m); for(int i=0;i<m;i++) { int u=a[i].u,v=a[i].v,w=a[i].w; int fa=find(u); int fb=find(v+1); if(fa!=fb) { p[fa]=p[fb]; ans+=w; cnt++; } if(cnt==n)break; } if(cnt<n)puts("-1"); else cout<<ans<<endl; return 0; }View Code
J.克隆
https://ac.nowcoder.com/acm/contest/8564/J
題解:求出2n-1的尤拉序,對於k個分身每個分身分配(2*n+k-1)/k個序列,則一定存在解。
#include<bits/stdc++.h> using namespace std; const int N=1e5+10,M=4e5+10; int h[N],e[M],ne[M],p[M],idx,cnt,n,m,k; int vis[N]; void add(int a,int b) { ne[idx]=h[a]; e[idx]=b; h[a]=idx++; } void dfs(int u) { vis[u]=1; p[cnt++]=u; for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(vis[j])continue; dfs(j); p[cnt++]=u; } } int main() { memset(h,-1,sizeof h); cin>>n>>m>>k; puts("YES"); for(int i=0;i<m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1); m=(2*n+k-1)/k; cnt--; int ans=cnt/m; int res=cnt%m,r=0; for(int i=1;i<=ans;i++) { printf("%d",m); for(int j=0;j<m;j++) printf(" %d",p[r++]); puts(""); } if(res) { printf("%d",res); for(int i=0;i<res;i++) printf(" %d",p[r++]); puts(""); } return 0; }View Code