Codeforces Round #633 (Div. 2)

A. Filling Diamonds

题意:

(交的时候也没搞懂这个题意,犹豫好久)用一个菱形覆盖一个"4n−2triangles"的不同覆盖方法

思路:

可以看出来有n种覆盖方法

代码:

#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
const int N=100010;
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        cout<<n<<endl;
    }
    return 0;
}

B. Sorted Adjacent Differences

题意:

给出一个长度为n的序列:\(a_1,a_2,…,a_n\),构造一种序列重排后满足:\(|a_1−a_2|≤|a_2−a_3|≤…≤|a\)n-1\(−a_n|\),输出任意一种方案。

思路:

这种题我们一般都先按从小到大排序,然后找到某种合适的顺序。排序后可以这样构造:\(a_1\)\(a_n\)的差值是最大的,然后让\(a_1,a_n\)排到最后,\(a_1\)\(a\)n-1的差小于等于\(a_1\)\(a_n\)的差,但是大于不包含\(a_n\)的其他所有。所有用双指针从前和从后接替加入。

代码:

#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
const int N=100010;
int a[N];
vector<int> v;
int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+1+n);
        v.clear();
        for(int i=1;i<=n/2;++i){
            v.push_back(a[i]);
            v.push_back(a[n-i+1]);
        }
        if(n%2){
            v.push_back(a[n/2+1]);
        }
        reverse(v.begin(),v.end());
        for(auto it: v) cout<<it<<" ";
        cout<<endl;
    }
    return 0;
}

C. Powered Addition

题意:

给出一个序列长度为n的序列,然后可以进行无数次操作,第i次可以选择任意个数(可以一个都不选),将其加上2i-1,求将序列变成非降序序列的最少操作次数。 \(1≤n≤10^5,−10^9≤a_i≤10^9\)

思路:

我们让\(a[i-1]>a[i],t=a[i-1]-a[i]\),t的二进制最高位1的位数就是我们使得a[i-1]<=a[i]的最小操作次数,所以当我们让a[i-1]=a[i]使用的是最小操作次数,且对于后面的限制更小,所以枚举所有不合法的前后差值,更新最高位1的位数就是答案。

代码:

#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
long long a[100010],p[60];
int main(){
    int T;
    p[0]=1;
    for(int i=1;i<60;++i){
        p[i]=p[i-1]*2;
    }
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%lld",&a[i]);
        }
        int ans=0;
        for(int i=2;i<=n;++i){
            if(a[i-1]>a[i]){
                LL t=a[i-1]-a[i];
                int res=0;
                //cout<<t<<endl;
                while(t){
                    res++;
                    t>>=1;
                }
                ans=max(ans,res);
                a[i]=a[i-1];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

D. Edge Weight Assignment

题意:

给出一个无权树,给每个边上赋一个权值,使得每两个叶子节点之间的路径边权异或和位0,求权值数的种类的最少和最多各为多少。\(3≤n≤10^5\)

思路:

数最少的情况:
当两个叶子节点之间的边数为偶数,那么这条路上的只用一种数就可以了。当边数奇数时,我们也只需要三个数就可以了:假设a-b之间边数为奇数,对于这一条单一的路径至少需要三个数是显然的,假设这条路径上有别另一条分支点d引出叶子节点c,c到d的边可以构造成异或和等于a到d的异或和,这样c到a的异或和为0,由于c到b和a到b一样,所以c到b异或和也为0.
数最多的情况:
若n-1条边权值都不相等,假设a到b的m条边都不相等,异或和为0,若有a的父亲节点d有另一个儿子节点c也是叶子,那么a到b的边数是2,则a到d和c到d的边权值相等,所以遍历一遍减去满足这种情况的边数。

代码:

#include<iostream>
#include<string.h>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
const int N=100010;
vector<int> g[N];
int dis[N],ans1,ans2;
bool dfs1(int u,int fa){
    dis[u]=dis[fa]+1;
    if(dis[u]%2&&g[u].size()==1) {
        ans1=3;
       //cout<<u<<endl;
        return true;
    }
    for(int i=0;i<g[u].size();++i){
        int v=g[u][i];
        if(v==fa) continue;
        if(dfs1(v,u)) return true;
    }
    return false;
}
void dfs2(int u,int fa){
    int cnt=0;
    for(int i=0;i<g[u].size();++i){
        int v=g[u][i];
        if(fa==v) continue;
        if(g[v].size()==1) cnt++;
        else dfs2(v,u);
    }
    if(cnt>0){
        ans2-=cnt-1;
    }
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1,u,v;i<n;++i) {
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    ans1=1,ans2=n-1;
    int f1=0,f2=0;
    for(int i=1;i<=n;++i){
        if(g[i].size()==1&&!f1){
            dis[0]=-1;
            dfs1(i,0);f1=1;
        }
        if(g[i].size()>1&&!f2) {
            dfs2(i,0);f2=1;
        }
    }
    cout<<ans1<<" "<<ans2<<endl;
    return 0;
}
posted @ 2020-04-15 00:42  0x4f  阅读(135)  评论(0编辑  收藏  举报