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\n",num);
    }
}

B. Maximum Product

思路:首先题意直接转化为从a数组中取五个数,使这五个数相乘的答案最大。那么把数组从大到小排序。然后考虑有负数,那么答案就是
1、\(a[1]\times a[2]\times a[n-2]\times a[n-1]\times a[n]\)
2、\(a[1]\times a[2]\times a[3]\times a[4]\times a[n]\)
3、\(a[n-4]\times a[n-3]\times a[n-2]\times a[n-1]\times 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\n",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\n",minNode,minBalance);
        if(num[minBalance].size()==1){
            printf("1 %d\n",tree[1][0]);
            printf("1 %d\n",tree[1][0]);
        }else{
            //printf("%d %d\n",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\n",u,v);
                    printf("%d %d\n",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\right]\)加上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\n",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\n",max(num+tot,differ[1]-num));
		    }
		    return 0;
		}
posted @ 2020-09-14 20:44  hachuochuo  阅读(129)  评论(0编辑  收藏  举报