AtCoder Beginner Contest 173 (D-F)

题目链接
D.Chat in a Circle
手玩一下发现,除了最大的数,其他的数最多能加两次。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<<x<<endl;
int n,a[N];
int main() {
  ios::sync_with_stdio(false);
  cin>>n;
  for(int i=1;i<=n;i++)cin>>a[i];
  sort(a+1,a+1+n,greater<int>());LL ans=a[1];
  int f=n-2,l=2;
  while(f>0){
    ans+=a[l];
    f--;if(!f)break;
    ans+=a[l];f--;l++;
  }
  cout<<ans<<'\n';
  return 0;
}

E - Multiplication 4
分类讨论。
1.先看<0,>0的数够不够k个,不够答案显然为0
2.看答案是否>0
----2.1如果答案>0,那么显然是选偶数个<0的,剩下全是>0的,如果k是奇数的话先拿一个>0最大的,然后贪心每次从>0,<0里面 拿两个乘积最大的。
3.答案<0的时候:那么显然贪心拿绝对值最小的。。。特判一下=0的情况

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,k,a[N],dx[N],dy[N];
const LL mod=1e9+7;
LL px[N],py[N];
long double lg[N],gl[N];
int main() {
  ios::sync_with_stdio(false);
  cin>>n>>k;int x=0,y=0,z=0;
  for(int i=1;i<=n;i++)cin>>a[i];
  for(int i=1;i<=n;i++){
    if(a[i]>0){
      dx[++y]=a[i];
    }else if(a[i]<0){
      dy[++z]=a[i];
    }else{
      x++;
    }
  }
  if(z+y<k)cout<<0<<'\n';
  else{
    sort(dx+1,dx+1+y,[](int x,int y){return x>y;});//++
    sort(dy+1,dy+1+z);//--
    int st=0;
    for(int i=0;i<=min(z,k);i+=2){
      if(k-i<=y)st=1;
    }
    if(!st){//必是负数
      if(x)return cout<<0,0;
      sort(dx+1,dx+1+y);
      sort(dy+1,dy+1+z,greater<int>());
      int dl=1,dr=1;
      LL temp=1;
      while(k){
        if(dl<=y && dr<=z){
          if(dx[dl]<abs(dy[dr])){
            temp*=dx[dl];
            temp%=mod;
            dl++;
          }else{
            temp*=dy[dr];
            temp%=mod;
            dr++;
          }
        }else if(dl<=y){
          temp*=dx[dl];
          temp%=mod;
          dl++;
        }else{
          temp*=dy[dr];
          temp%=mod;
          dr++;
        }
        k--;
      }
      cout<<(temp+mod)%mod;
    }else{
      sort(dx+1,dx+1+y,greater<int>());
      sort(dy+1,dy+1+z);
      LL temp=1;
      int l=1,r=1;
      if(k&1)temp*=dx[l++],temp%=mod,k--;
      while(k){
        if(y-l>=1 && z-r>=1){
          if(1ll*dx[l]*dx[l+1]>=1ll*dy[r]*dy[r+1]){
            temp*=dx[l];
            temp%=mod;
            temp*=dx[l+1];
            temp%=mod;
            l+=2;
            k-=2;
          }else{
            temp*=dy[r];
            temp%=mod;
            temp*=dy[r+1];
            temp%=mod;
            r+=2;
            k-=2;
          }
        }else if(y-l>=1){
          temp*=dx[l];
          temp%=mod;
          temp*=dx[l+1];
          temp%=mod;
          l+=2;
          k-=2;
        }else if(z-r>=1){
          temp*=dy[r];
          temp%=mod;
          temp*=dy[r+1];
          temp%=mod;
          r+=2;
          k-=2;
        }
      }
      cout<<(temp+mod)%mod<<'\n';
    }
  }
  return 0;
}

F - Intervals on Tree
树的 顶点数=边数+1
那么一个森林的 顶点数=边数+联通块数量
f ( L , R ) f(L,R) 代表的一个点集构成的必然是一个森林,联通快数量=R-L+1 - 边数
顶点的总和可以很容易计算,那么我们去掉边数,对每个边单独考虑,计算每个边被多少个点集包括即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
#define debug(x) cerr<<"x ="<<x<<endl
int n;
int main() {
  ios::sync_with_stdio(false);
  cin>>n;LL ret=0;
  for(int i=1;i<=n;i++){
    ret+=1ll*(n-i+2)*(n-i+1)/2;
  }
 // debug(ret);
  for(int i=1;i<n;i++){
    int s,t;
    cin>>s>>t;
    if(s>t)swap(s,t);
    ret-=1ll*s*(n-t+1);
  }
  cout<<ret<<'\n';
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40655981/article/details/107156038