Codeforces Round #525 (Div. 2)

题目直通车:http://codeforces.com/contest/1088


A - Ehab and another construction problem

  开心一下

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k,ar[maxn];


int main()
{
    scanf("%d",&n);
    if(n==1)printf("-1
");
    else printf("%d %d
",n,n);
    return 0;
}
View Code

B - Ehab and subtraction

  排序之后以此输入当前值和前缀和的差值即可,注意差值为0时要跳过

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k,ar[maxn];


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",ar+i);
    int ins=0;
    sort(ar+1,ar+n+1);
    ll pre=0,ans=0;
    for(int i=1;i<=m;i++){
        ins++;
        while(ins<=n && ar[ins]==pre)ins++;
        if(ins<=n)ans=ar[ins]-pre,pre=ar[ins];
        else ans=0;
        printf("%lld
",ans);
    }
    return 0;
}
View Code

C - Ehab and a 2-operation task

  题目设定n+1其实说的很明显了

  设置n次+操作,1次%操作,每次+操作使得序列的每一个值对一个大数(1000000)的模为递减序列即可,例如我的最后一个模值为999999,往前以此递减

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k,ar[maxn];

ll mx=1000000;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",ar+i);
    printf("%d
",n+1);
    ll ins=999999;
    ll pre=0;
    for(int i=n;i>=1;i--){
        ll ans=(ins-(pre+ar[i])%mx+mx)%mx;
        pre += ans;
        printf("1 %d %lld
",i,ans);
        ins--;
    }
    printf("2 %d %lld
",n,mx);
    return 0;
}
View Code

D - Ehab and another another xor problem

  考虑二进制查询,根据最多需要62次的提示可知,平均每两次查询需要得到a,b当前的二进制位值,二进制位共有(1,0),(1,1),(0,0),(0,1)四种情况,可以用一次查询来得出当前a,b的大小情况(查询? 0 0),假设a<b,则共有(0,0),(0,1),(1,1)三种情况,,此时发现,如果a,b在该二进制位上相等的话,,下次就不需要再进行大小判断的查询(节省一次查询),,则就可以想到,在本次查询中,希望能用一次来确定a,b是不是(0,1)的情况,而可以用两次来判断是(0,0)或者(1,1)(下一个二进制位不需要大小判断而节省下来的一次查询机会),则可以用print(! a|(1<<ins),b|(1<<ins))(ins为当前查询的二进制位),此时如果得到的是大于,则可以判定a,b的在二进制的ins位上为(0,1),否则,再用一次print(! a|(1<<ins),b)来确定本二进制位是(0,0)还是(1,1);反之,相同;

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k,ar[maxn];

bool fond=0;
int a,b;
int main()
{
    a=0,b=0;
    fond=0;
    int pre=-2,ins=29,mid;
    while(ins>=0){
        if(pre==-2){
            printf("? %d %d
",a,b);
            fflush(stdout);
            mid=pre;
            scanf("%d",&pre);
        }
        else if(pre==-1){
            printf("? %d %d
",a|(1<<ins),b|(1<<ins));
            fflush(stdout);
            scanf("%d",&pre);
            if(pre==1){
                b |= (1<<ins);
                ins--;
                pre=-2;
            }
            else{
                mid=pre;
                pre=0;
            }
        }
        else if(pre==1){
            printf("? %d %d
",a|(1<<ins),b|(1<<ins));
            fflush(stdout);
            scanf("%d",&pre);
            if(pre==-1){
                a |= (1<<ins);
                ins--;
                pre=-2;
            }
            else{
                mid=pre;
                pre=0;
            }
        }
        else if(pre==0){
            pre=mid;
            printf("? %d %d
",a|(1<<ins),b);
            fflush(stdout);
            scanf("%d",&mid);
            if(mid==1){
                //cout<<"input 0
";
                ins--;
            }
            else{
                //cout<<"input 1
";
                a |= (1<<ins);
                b |= (1<<ins);
                ins--;
            }
        }
        //cout<<"pre = "<<pre<<endl;
    }
    printf("! %d %d
",a,b);
    return 0;
}
View Code

E - Ehab and a component choosing problem

  题意:取k个联通块,使得所取的点的权值和/k最大,相等时,k最大

  以权值最大的点为根,dfs遍历图,如果当前联通块权值和为+,即对父节点的贡献为正,否则无贡献,求出权值最大的联通块即可(k==1),重点在于如何使得联通块无重合的情况下k尽量大,此时需要新加一个变量来说明当前联通块是否对答案有贡献,如果有且根父节点所在联通块的最大值一样的话,不能同时对k做贡献,相应控制此变量即可(代码中的my);

  需要注意的是,当父节点的一个子节点更新了最大值时,之前遍历的其他子节点对答案的贡献要清零,即重置my变量

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k;
ll ar[maxn],mn=-1e16-1;
vector<int> ve[maxn];
ll a1,a2;
ll dfs(int u,int fa,bool& my){
    ll son=ar[u];
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==fa)continue;
        bool ss=0;
        ll pre=a1;
        ll mid=dfs(v,u,ss);
        if(mid!=mn){
            son+=mid;
            my |= ss;
        }
        if(a1>pre && ss==0)my=0;//如果最大值改变且当前子节点不对答案有贡献,则my清零
    }
    if(son>a1){
        a1=son;
        a2=1;
        my=1;
    }
    else if(son==a1 && my==0){
        a2++;
        my=1;
    }
    if(son>0)return son;
    my=0;
    return mn;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",ar+i);
    for(int i=1;i<n;i++){
        int a,b;scanf("%d%d",&a,&b);
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    ll mid=mn,ins=0;
    for(int i=1;i<=n;i++){
        if(mid<ar[i]){
            mid=ar[i];
            ins=i;
        }
    }
    bool my=0;
    a1=mn,a2=1;
    dfs(ins,0,my);
    printf("%lld %lld
",a1*a2,a2);
    return 0;
}
/*
input:
4
3 -3 3 3
1 2
2 3
3 4
output:
6 1

*
View Code

F - Ehab and a weird weight formula

  由given tree的性质可以知道,以最小权值的节点作为根节点dfs的话,每个子节点权值都比父节点要大

  对每一个子节点,可以将他的父节点重置为他的某个祖先节点(把该节点作为相应祖先节点的子节点),在离祖先节点距离为同一个ceil(dist(u,v))时,肯定是祖先节点越远越好(贪心),即需要遍历离此节点距离为1,2,4,8,16。。。的祖先节点,求对答案贡献值最小的祖先节点即可。复杂度nlog

#include<bits/stdc++.h>
using namespace std;
#define freread freopen("input.txt","r",stdin);
#define frewrite freopen("output.txt","w",stdout);
typedef long long ll;
const int maxn=5e5+7;
int n,m,k,ar[maxn];
vector<int> ve[maxn];
int mn[maxn],len;
ll ans;
void dfs(int u,int fa){
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==fa)continue;
        mn[++len]=ar[v];
        ll mid=1e12+1;
        for(int j=0;j<20;j++){
            int x=len-(1<<j);
            x=max(x,1);
            mid=min(mid,1LL*mn[x]*(j+1));
            if(x==1)break;
        }
        ans += ar[v];
        ans += mid;
        dfs(v,u);
        len--;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",ar+i);
    for(int i=1;i<n;i++){
        int a,b;scanf("%d%d",&a,&b);
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    int ins=0,mx=1e9+1;
    for(int i=1;i<=n;i++){
        if(mx>ar[i]){
            mx=ar[i];
            ins=i;
        }
    }
    ans=0;
    len=0;
    mn[++len]=ar[ins];
    dfs(ins,0);
    printf("%lld
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/wa007/p/10072006.html