1. 程式人生 > 實用技巧 >牛客小白月賽29

牛客小白月賽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;
        
return 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; }
View Code

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