Codeforces Round #591 (Div. 2, based on Technocup 2020 Elimination Round 1) 題解

A..B略

C 對當前的值排序,再二分答案,然後對於(i%x==0 && i%y==0)放入大的,再放其他的貪心解決即可。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#define LL long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxx = 2e5+7;
int a[maxx];
int vis[maxx];
LL k;
LL aa,bb;
int x,y,n;
bool check(int mid){
      LL ans=0;
      int top=0;
       for (int i=1;i<=mid;i++){
            if (i%x==0 && i%y==0){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*(aa+bb);
            }else {
                vis[i]=0;
            }
 
        }
        for (int i=1;i<=mid;i++){
            if (i%y==0 && !vis[i]){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*bb;
            }
 
        }
        for (int i=1;i<=mid;i++){
            if (i%x==0 && !vis[i]){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*aa;
            }
        }
        return ans>=k;
}
bool cmp(int x,int y){
   return x>y;
}
int main(){
  int t;
  scanf("%d",&t);
  while(t--){
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
      scanf("%d",&a[i]);
    }
    scanf("%d%d",&aa,&x);
    scanf("%d%d",&bb,&y);
    scanf("%lld",&k);
    if (aa>bb){
        swap(x,y);
        swap(aa,bb);
    }
    sort(a+1,a+1+n,cmp);
    int l=1;
    int r=n;
    int ans=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if (check(mid)){
            ans=mid;
            r=mid-1;
        }else {
            l=mid+1;
        }
    }
    if (ans==-1){
        printf("-1\n");
    }else {
        printf("%d\n",ans);
    }
  }
  return 0;
}

D 記錄一次出現和最後一次出現的,考慮移動的比較麻煩,我們可以考慮對於兩個相鄰的大小的值,前面那個值最後次出現的位置是大於這個值第一次出現的,那麼他們的相對位置關係是不用移動的,我們求出這種不用移動的相對位置連續個數是最多的,那麼就是最長不用移動的,其他的肯定要移動,那麼直接用所有值的個數去減這個值就行了。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#define LL long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxx = 2e5+7;
int a[maxx];
int vis[maxx];
LL k;
LL aa,bb;
int x,y,n;
bool check(int mid){
      LL ans=0;
      int top=0;
       for (int i=1;i<=mid;i++){
            if (i%x==0 && i%y==0){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*(aa+bb);
            }else {
                vis[i]=0;
            }
 
        }
        for (int i=1;i<=mid;i++){
            if (i%y==0 && !vis[i]){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*bb;
            }
 
        }
        for (int i=1;i<=mid;i++){
            if (i%x==0 && !vis[i]){
                vis[i]=a[++top];
                ans=(LL)ans+vis[i]/100*aa;
            }
        }
        return ans>=k;
}
bool cmp(int x,int y){
   return x>y;
}
int main(){
  int t;
  scanf("%d",&t);
  while(t--){
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
      scanf("%d",&a[i]);
    }
    scanf("%d%d",&aa,&x);
    scanf("%d%d",&bb,&y);
    scanf("%lld",&k);
    if (aa>bb){
        swap(x,y);
        swap(aa,bb);
    }
    sort(a+1,a+1+n,cmp);
    int l=1;
    int r=n;
    int ans=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if (check(mid)){
            ans=mid;
            r=mid-1;
        }else {
            l=mid+1;
        }
    }
    if (ans==-1){
        printf("-1\n");
    }else {
        printf("%d\n",ans);
    }
  }
  return 0;
}

E. Paint the Tree

  我們考慮dp[i][0]代表這個節點的k重顏色已經全部匹配,dp[i][0代表當前節點還有顏色沒有匹配。那麼我們其實可以很容易得到dp的轉移

  首先dp[i][1]+=sigma[son[i]][0] dp[i][0]+=sigma[son[i]][0] 也就是說我們每個節點首先看出全部選了子樹顏色已經全部匹配的結果

  我們再把所有節點選擇子樹沒有匹配完全的加上這條路徑的長度去減去子樹已經匹配的完全的差值,然後再差值中選中前k大的正數和加到dp[i][0]表示選擇後悔了

把前i-1的正數加到dp[i][1]中即可。最後取根節點兩者的最大值即可。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
const int maxx = 5e5+6;
int ver[maxx*2],edge[2*maxx],head[maxx],Next[2*maxx];
int n,k,tot;
LL dp[maxx][2];
void add(int x,int y,int w){
   ver[++tot]=y;edge[tot]=w;Next[tot]=head[x];head[x]=tot;
   ver[++tot]=x;edge[tot]=w;Next[tot]=head[y];head[y]=tot;
}
bool cmp(int a,int b){
   return a>b;
}
void dfs(int u,int fa){
   dp[u][0]=dp[u][1]=0;
   vector<int>vv;
   vv.clear();
   for (int i=head[u];i;i=Next[i]){
       int v=ver[i];
       if (v==fa)continue;
       dfs(v,u);
       dp[u][0]+=dp[v][0];
       dp[u][1]+=dp[v][0];
   }
   for (int i=head[u];i;i=Next[i]){
       int v=ver[i];
       if (v==fa)continue;
       vv.push_back(dp[v][1]+edge[i]-dp[v][0]);
   }
   sort(vv.begin(),vv.end(),cmp);
   int sz=min((int)vv.size(),k);
   for (int i=0;i<sz;i++){
       if(vv[i]<0)break;
       if(i==k-1){
          dp[u][0]=(LL)vv[i]+dp[u][1];
       }else {
          dp[u][0]=(LL)vv[i]+dp[u][1];
          dp[u][1]=(LL)vv[i]+dp[u][1];
       }
   }
}
int main(){
  int t;
  scanf("%d",&t);
  int uu,vv,ww;
  while(t--){
     scanf("%d%d",&n,&k);
     for (int i=1;i<=n;i++){
        head[i]=0;
     }
     for (int i=1;i<=n-1;i++){
        scanf("%d%d%d",&uu,&vv,&ww);
        add(uu,vv,ww);
     }
     dfs(1,-1);
     printf("%lld\n",max(dp[1][0],dp[1][1]));
  }
  return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章