More than 2019 cattle off summer school camp (four)

Disclaimer: This article topics are the source of the cattle off network

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

A-meeting

Question Types: DFS, BFS

Topic links: https://ac.nowcoder.com/acm/contest/884/A

Subject to the effect

To n city, city to city, a total of the n-1 (that is, a tree of n nodes) connected edges, then there are k people (k take tree nodes) in different cities, they decided to gather in one city, every time a road to the demands of 1, find that individual k shortest time needed to gather together. (N-<10 . 5 )

Topic understand

First, the longest of the last two points must be together, and meet in the middle point of this longest way.

This required the longest path may start with any point within DFS or BFS find a pseudo longest path, and then again by the other end of this time the dummy longest path DFS or BFS find the longest path required, that is, to find the diameter of the tree.

Proof: as shown below

 

图中 AO <BO, CO <DO, BO <DO

Yes AO + DO <DO + OB

 

A selected set point at any point, for DFS traversal to obtain the longest path AD is false, then the DFS then from point B to BD (the diameter of the tree) the longest path.

So to solve this problem is available twice DFS, final output (the longest path +1) / 2 (half the shortest time longer).

AC Code

#include<iostream>
#include<vector>
using namespace std;
vector<int> v[100010];
int loc[100010],ans=0,res;
void dfs(int now,int p,int len){
    if(loc[now]&&len>ans){
        ans=len;
        res=now;
    }
    int y=v[now].size();
    for(int i=0;i<y;i++){
        int next=v[now][i];
        if(next==p) continue;
        dfs(next,now,len+1);
    }
}
int main(){
    int n,k;
    cin >> n >> k;
    for(int i=0;i<n-1;i++){
        int v1,v2;
        cin >> v1 >> v2;
        v[v1].push_back(v2);
        v[v2].push_back(v1);    
    }
    while(k--){
        int x;
        cin >> x;
        loc[x]=1;
    }
    dfs(1,1,0);
    dfs(res,res,0);
    cout << (ans+1)/2;
    return 0;
}

postscript

Diameter topic study tree, the tree usually do less of the subject, and when the game did not carefully read the title and think, lead to sign the title did not do anything.

B-xor

Liver blast ~

C-sequence

Question Types: divide and conquer, tree line

Topic links: https://ac.nowcoder.com/acm/contest/884/C

Subject to the effect

There are two arrays a and b n array elements, seeking a [l, r] interval, so that a the array elements in this minimum of the interval on by elements of the array and b in this range of the maximum number obtained.

(n < 3e6,-1e< ( ai,bi ) < 1e6)

D-triples I

Question Types: bitwise OR, thinking

题目链接:https://ac.nowcoder.com/acm/contest/884/D

题目大意

输入T个数,每个数都能由3的倍数按位或得来,对于输入的数a,输出任意一组3的倍数,这些数的按位或的结果等于a。(1 < T < 1e5,1 < a < 1e18

题目理解

一个简单的数字构造题。对于一个数a,a模上3的结果只可能为0、1、2。

如果为0,则输出a即可;

如果不为0,则将其转化为二进制。比如样例中的7,将7写成二进制,为111,其二进制每一位代表的数字模3为121(4%3=1,2%3=2,1%3=1),

得规律:如果二进制位1所在位置为奇数位,则模3为1,偶数位则为2。

  • 如果a%3=1。如果a的二进制有两个及以上的奇数位的1,假设b为一个奇数位的1代表的数字,再假设c为另一个奇数位的1代表的数字,按照上面所讲的规律,a-b和a-c都为3的倍数,根据按位或的性质(只要为1则为1),(a-b) | (a-c) = a。如果二进制只有一个奇数位的1,设b为这个1代表的数字,c为任意一个偶数位1所代表的数字,a-b和b+c都为3的倍数,且(a-b) | (b+c) = a。如果二进制没有奇数位的1,设b,c,d为任意3个不同的偶数位所代表的数字,a-b-c和a+b+c为3的倍数,且(a-b-c) | (b+c+d)
  • 如果a%3=2。原理和上面一样,只需要将每一步的奇偶性反过来就行了,这里就不说了。

总结:就用原来的数字a构造3的倍数,去掉模3的有余数的数就行了,而且联想一下可以发现,只需要最多两个3的倍数就可以按位或成数字a。

AC代码

#include<iostream>
#include<vector>
#define sc(x) scanf("%d",&x);
#define scll(x) scanf("%lld",&x);
using namespace std;
typedef long long ll;
int main(){
    int t;sc(t);
    while(t--){
        ll n;scll(n);
        vector<int> one,two;
        for(int i=0;i<62;i++)
            if((n>>i)&1){//用vector容器分别保存二进制位奇偶性不同的1的位置 
                if(i&1) two.push_back(i); //保存偶数位1 
                else one.push_back(i);//保存奇数位1 
            } 
        if(n%3==0) printf("1 %lld\n",n);
        else if(n%3==1){
            if(one.size()>=2) 
                printf("2 %lld %lld\n",n-(1LL<<one[0]),n-(1LL<<one[1]));
            else if(one.size()==1)  
                printf("2 %lld %lld\n",n-(1LL<<one[0]),(1LL<<two[0])+(1LL<<one[0]));
            else 
                printf("2 %lld %lld\n",n-(1LL<<two[0])-(1LL<<two[1]),(1LL<<two[0])+(1LL<<two[1])+(1LL<<two[2]));
        }else if(n%3==2){
            if(two.size()>=2) 
                printf("2 %lld %lld\n",n-(1LL<<two[0]),n-(1LL<<two[1]));
            else if(two.size()==1) 
                printf("2 %lld %lld\n",n-(1LL<<two[0]),(1LL<<two[0])+(1LL<<one[0]));
            else 
                printf("2 %lld %lld\n",n-(1LL<<one[0])-(1LL<<one[1]),(1LL<<one[0])+(1LL<<one[1])+(1LL<<one[2]));
        }
    }
    return 0;
}

反思

构造题,找规律,也要看自己对位运算的理解以及运用。

j-free

题目类型:分层图最短路

题目链接:https://ac.nowcoder.com/acm/contest/884/J

题目大意

有一个非直接连接的图,n个结点,m条边,每条边有花费l,要求在可以让k条边权值为0的情况下,求s点到t点的最小花费。

(1 <= n,m <= 1e3,1 <= s,t <= n,1 <= l <= 1e6

题目理解

一道分层图最短路模板题,把保存花费的d数组多开一维记录k次机会的信息。d[ i ][ j ]达到 i 点用了 j 次机会的最小花费。

更新信息的时候先更新同一层的(用了相同次机会)最小花费,然后再更新下一层的(再用一次机会)最小花费。

dijkstra最短路就行了(用优先队列维护)。

AC代码

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,s,t,k,d[1010][1010];
typedef pair<int,int> P;
struct node{
    int to,cost;
    node(int a,int b){
        to=a;
        cost=b;
    }
};
vector<node> v[1010];
void dijkstra(int s){ 
    memset(d,inf,sizeof(d));
    d[s][0]=0;
    queue<P> que;
    que.push(P(s,0));
    while(!que.empty()){
        P now=que.front();
        que.pop();
        int u=now.first,t=now.second;
        for(int i=0;i<v[u].size();i++){
            int x=v[u][i].to;
            int pay=v[u][i].cost;
            if(d[x][t]>d[u][t]+pay) //更新同层的最小花费 
                d[x][t]=d[u][t]+pay,que.push(P(x,t));
            if(t<k&&d[x][t+1]>d[u][t]) //更新下一层的最小花费 
                d[x][t+1]=d[u][t],que.push(P(x,t+1));
        }
    }
}
int main(){
    cin >> n >> m >> s >> t >> k;
    while(m--){
        int a,b,c;
        cin >> a >> b >> c;
        v[a].push_back(node(b,c));
        v[b].push_back(node(a,c));
    } 
    dijkstra(s);
    int ans=inf;
    for(int i=0;i<=k;i++)
        ans=min(ans,d[t][i]);
    printf("%d",ans);
    return 0;
} 

后记

要不是出了这题我还不知道分层图这个东西,还是练习太少的锅。

Guess you like

Origin www.cnblogs.com/lastonepersonwhohavebitenbycompanies/p/11259203.html