• Codeforces Round #670 (Div. 2)(A B C D)


    题目列表

    • A. Subset Mex
    • B. Maximum Product
    • C. Link Cut Centroids
    • D. Three Sequences

    Practice link:https://codeforces.ml/contest/1406


    A. Subset Mex

    思路:从小到大遍历,出现两次及以上的数字一定不会是mex,答案一定是出现次数为1的最小数字加上出现次数为0的最小数字。
    代码:

    #define MOD 1000000007
    #define ll long long
    #define mem(a,x) memset(a,x,sizeof(a))
    #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    using namespace std;
    const double eps = 1e-4;
    const long long INF = 0x3f3f3f3f3f3f3f3fLL;
    const int inf = 0x3f3f3f3f;
    int a[105];
    int sum[105];
    int main()
    {
        int T,n;
     
        scanf("%d",&T);
        while(T--){
            mem(sum,0);
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                sum[a[i]]++;
            }
            sort(a+1,a+n+1);
            int k=-1;
            int num=0;
            for(int i=0;i<=100;i++){
                if(sum[i]>=2)continue;
                if(sum[i]==1&&k==-1){
                   num+=i;
                   k=i;
                }
                if(sum[i]==0&&k!=-1){
                    num+=i;
                    break;
                }
                if(sum[i]==0&&k==-1){
                    num+=i*2;
                    break;
                }
            }
            printf("%d
    ",num);
        }
    }
    

    B. Maximum Product

    思路:首先题意直接转化为从a数组中取五个数,使这五个数相乘的答案最大。那么把数组从大到小排序。然后考虑有负数,那么答案就是
    1、(a[1] imes a[2] imes a[n-2] imes a[n-1] imes a[n])
    2、(a[1] imes a[2] imes a[3] imes a[4] imes a[n])
    3、(a[n-4] imes a[n-3] imes a[n-2] imes a[n-1] imes a[n])
    这三个数中取max即可。
    代码:

    const long long INF = 0x3f3f3f3f3f3f3f3fLL;
    const int inf = 0x3f3f3f3f;
    ll a[100005];
     
    int main()
    {
        int T,n;
     
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%lld",&a[i]);
            }
            sort(a+1,a+n+1);
            ll num=-INF;
            num=max(num,a[1]*a[2]*a[n]*a[n-1]*a[n-2]);
            num=max(num,a[n]*a[n-1]*a[n-2]*a[n-3]*a[n-4]);
            num=max(num,a[1]*a[2]*a[3]*a[4]*a[n]);
            printf("%lld
    ",num);
        }
    }
    

    题意:让你在一棵树中去掉一条边,然后添加一条边,让这棵树的重心唯一。
    思路:首先dfs求出树的重心,如果只有一个重心,那么随便去掉一条,再添加回来即可。如果有两个重心,那么去掉两个重心的连线,然后用其中一个重心去连接另一个重心的子树上的随意一点即可。
    代码:

    const int maxn = 100005 ;
    vector<int>tree[maxn];
    vector<int>num[100005];
    int minNode,minBalance;
    //minNode 表示当前的重心
    //minBalance 表示当前重心下的最大子树结点个数
    int d[maxn];
    //d[i]表示以 i 为根的子树结点数
    int n;
    void getCentroid(int u,int fa)
    {
        d[u]=1;
        int maxsub=0;
        for(int i=0;i<tree[u].size();i++){
            int v=tree[u][i];
            if(v==fa)continue;
            getCentroid(v,u);
            d[u]+=d[v];
            maxsub=max(d[v],maxsub);
        }
        maxsub=max(maxsub,n-d[u]);
        if(maxsub<minBalance){
            minNode=u;
            minBalance=maxsub;
            num[maxsub].push_back(u);
        }else if(maxsub==minBalance){
            num[maxsub].push_back(u);
        }
    }
    vector<int>gg;
    void dfs(int u,int fa)
    {
        if(gg.size()==1)return;
        if(tree[u].size()==1){
           gg.push_back(u);
           return;
        }
        for(int i=0;i<tree[u].size();i++){
            int v=tree[u][i];
            if(v==fa)continue;
            dfs(v,u);
        }
    }
    int main()
    {
        int T;
        cin>>T;
        while(T--){
            cin>>n;
            gg.clear();
            for(int i=1;i<=n;i++){
                tree[i].clear();
                num[i].clear();
            }
            for(int i=1;i<n;i++){
                int u,v;
                scanf("%d %d",&u,&v);
                tree[u].push_back(v);
                tree[v].push_back(u);
            }
            minNode=0;
            minBalance=inf;
            getCentroid(1, 0);
            //printf("%d %d
    ",minNode,minBalance);
            if(num[minBalance].size()==1){
                printf("1 %d
    ",tree[1][0]);
                printf("1 %d
    ",tree[1][0]);
            }else{
                //printf("%d %d
    ",num[minBalance][0],num[minBalance][1]);
                int u=num[minBalance][1];
                int fa=num[minBalance][0];
                for(int i=0;i<tree[u].size();i++){
                    int v=tree[u][i];
                    if(v!=fa){
                        printf("%d %d
    ",u,v);
                        printf("%d %d
    ",num[minBalance][0],v);
                        break;
                    }
                }
            }
        }
        return 0;
    }
    

    D. Three Sequences

    题意:给你一个数组(a_{i}),让你去构造(b_{i})(c_{i})(b_{i})单调不增,(c_{i})单调不减,让你使max((b_{i}),(c_{i}))最小。在给你q次修改,把区间(left[ l,r ight])加上x,并求出 max((b_{i}),(c_{i}))。
    思路:

    代码:

    		#define ll long long
    		#define MOD 1000000007
    		#define mem(a,x) memset(a,x,sizeof(a))
    		#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    		using namespace std;
    		const long long INF = 0x3f3f3f3f3f3f3f3fLL;
    		const int inf = 0x3f3f3f3f;
    		const int MAXN=16005;
    		const int MAXM=80005;
    		 
    		int a[100005];
    		ll differ[100005];
    		int n,q;
    		ll tot=0;
    		int main()
    		{
    		    tot=0;
    		    scanf("%d",&n);
    		    for(int i=1;i<=n;i++){
    		        scanf("%d",&a[i]);
    		        if(i>1){
    		            differ[i]=a[i]-a[i-1];
    		            if(differ[i]>0){
    		               tot+=differ[i];
    		            }
    		        }
    		    }
    		    differ[1]=a[1];
    		    ll num=(differ[1]-tot)/2;
    		    printf("%lld
    ",max(num+tot,differ[1]-num));
    		    scanf("%d",&q);
    		    while(q--){
    		        int l,r;
    		        ll x;
    		        scanf("%d%d%lld",&l,&r,&x);
    		        if(l==1){
    		           differ[1]+=x;
    		        }else{
    		            if(x<0){
    		                if(differ[l]>0)tot-=min(differ[l],-x);
    		            }else{
    		                if(differ[l]+x>0)tot+=min(x,differ[l]+x);
    		            }
    		            differ[l]+=x;
    		        }
    		        if(r+1<=n){
    		            if(x>0){
    		                if(differ[r+1]>0){
    		                   tot-=min(differ[r+1],x);   
    		                }
    		            }else{
    		                if(differ[r+1]-x>0){
    		                    tot+=min(-x,differ[r+1]-x);
    		                }
    		            }
    		            differ[r+1]-=x;
    		        }
    		        num=(differ[1]-tot)/2;
    		        printf("%lld
    ",max(num+tot,differ[1]-num));
    		    }
    		    return 0;
    		}
    
    越自律,越自由
  • 相关阅读:
    POJ 1451
    LightOJ 1224
    POJ 2001
    HDU 2072
    POJ 3764
    CH 1602
    CH 1601
    Gym 101873K
    CH 1201
    Gym 101873C
  • 原文地址:https://www.cnblogs.com/ha-chuochuo/p/13669238.html
Copyright © 2020-2023  润新知