2019牛客多校训练(四)

比赛链接:

https://ac.nowcoder.com/acm/contest/884#question

A. meeting

题意:

给出一颗树

让所有染色点到某个点的最大距离最小

分析:

结果为最远点对的距离除二向上取整

假设有最远点对的路径上的中间点

如果有某个点它到这个中间点要远,那么最远点对就不是最远点对了,产生矛盾

利用树上点对路径唯一性,两次$dfs$求出染色点直径

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e5+10;
const ll mod=1e9+7;
struct Edge{
    int to,nex;
}edge[maxn*2];
int n,k,edge_num,head[maxn],dis[maxn],cor[maxn];
void add_edge(int u,int v)
{
    edge_num++;
    edge[edge_num].nex=head[u];
    edge[edge_num].to=v;
    head[u]=edge_num;
}
void dfs(int x){
    for(int i=head[x];i;i=edge[i].nex){
        int to=edge[i].to;
        if(dis[to]>dis[x]+1)dis[to]=dis[x]+1,dfs(to);
    }
}
int fin(int x)
{
    for(int i=1;i<=n;i++)dis[i]=1e9;
    dis[x]=0;
    dfs(x);
    int maxx=0,inde;
    for(int i=1;i<=k;i++)
        if(maxx<dis[cor[i]])maxx=dis[cor[i]],inde=cor[i];
    //for(int i=1;i<=k;i++)cout<<dis[cor[i]]<<" ";
    //cout<<endl;
    return inde;
}
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n-1;i++){
        int u,v;
        scanf("%d %d",&u,&v);
        add_edge(u,v);
        add_edge(v,u);
    }
    for(int i=1;i<=k;i++)scanf("%d",&cor[i]);
   // cout<<k<<endl;
    int node1=fin(cor[1]);
    int node2=fin(node1);
  //  cout<<node1<<" "<<node2<<endl;
    printf("%d
",(dis[node2]+1)/2);
    return 0;
}

  

D. triples I

题意:

用尽可能少的三的倍数异或出$a$

分析:

典型的构造题

首先,$2^{n}\%3$等于1或者2

1.如果$a\%3=0$,直接输出$a$

2.如果$a\%3=1$,去掉二进制某些位置,让$a$变成3的倍数即可

3.$a\%3=1$同理

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=3e6+10;
const ll mod=1e9+7;
vector<ll>ve1,ve2;
int main()
{
   // cout<<(48|24)<<endl;
    //cout<<((ll)1<<62)<<endl;
    int T;
    scanf("%d",&T);
    while(T--){
        ll a;
        scanf("%lld",&a);
        if(a%3==0){
            printf("1 %lld
",a);
            continue;
        }
        ve1.clear(),ve2.clear();
        for(int i=0;i<=62;i++){
            if(a&((ll)1<<i)){
                if(((ll)1<<i)%3==2)ve2.push_back((ll)1<<i);
                else ve1.push_back((ll)1<<i);
            }
        }
        printf("2 ");
        if(a%3==1){
            if(ve1.size()>=2){
                printf("%lld %lld
",a-ve1[0],a-ve1[1]);
            }else if(ve1.size()==1){
                printf("%lld %lld
",a-ve1[0],a-ve2[0]-ve2[1]);
            }else if(ve1.size()==0){
                printf("%lld %lld
",a-ve2[0]-ve2[1],a-ve2[2]-ve2[3]);
            }
        }
        else {
            if(ve2.size()>=2){
                printf("%lld %lld
",a-ve2[0],a-ve2[1]);
            }else if(ve2.size()==1){
                printf("%lld %lld
",a-ve2[0],a-ve1[0]-ve1[1]);
            }else if(ve2.size()==0){
                printf("%lld %lld
",a-ve1[0]-ve1[1],a-ve1[2]-ve1[3]);
            }
        }

    }
    return 0;
}
	triples I

J. free

题意:

给出一个图,最多让$k$条边花费变成0,求$s$到$t$的最短距离

分析:

对整个图分层,分成$k+1$层,第0层节点编号是$1$到$n$,第二次是$n+1$到$n+n$

建立层之间的边,并且允许第i层的点用0花费到达$i+1$层

调用迪杰斯特拉,最后的结果是$dis[k*n+t]$

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+10;
const ll mod=1e9+7;
int n,m,s,t,k,head[maxn],edge_num,dis[maxn];
bool vis[maxn];
struct Edge{
    int to,w,nex;
}edge[maxn*5];
void add_edge(int u,int v,int w)
{
   // cout<<"adge:"<<u<<" "<<v<<" "<<w<<endl;
    edge_num++;
    edge[edge_num].nex=head[u];
    edge[edge_num].to=v;
    edge[edge_num].w=w;
    head[u]=edge_num;
}
void dj()
{
    for(int i=1;i<=k*n+n;i++)dis[i]=1e9,vis[i]=0;
    priority_queue<pa>que;
    dis[s]=0;
    que.push(make_pair(0,s));
    while(que.size()){
        pa now=que.top();
        que.pop();
 
        if(vis[now.second])continue;
        vis[now.second]=1;
       // cout<<now.second<<endl;
        for(int i=head[now.second];i;i=edge[i].nex){
            int to=edge[i].to;
            int w=edge[i].w;
            if(dis[to]>dis[now.second]+w){
                dis[to]=dis[now.second]+w;
                que.push(make_pair(-dis[to],to));
            }
        }
 
    }
}
int main()
{
    scanf("%d %d %d %d %d",&n,&m,&s,&t,&k);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        for(int j=0;j<=k;j++){
            add_edge(u+j*n,v+j*n,w);
            add_edge(v+j*n,u+j*n,w);
            if(j!=k){
                add_edge(u+j*n,v+(j+1)*n,0);
                add_edge(v+j*n,u+(j+1)*n,0);
            }
        }
    }
    dj();
    printf("%d
",dis[k*n+t]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/carcar/p/11256879.html