Educational Codeforces Round 131 (Rated for Div. 2) A - D

Educational Codeforces Round 131 (Rated for Div. 2) A - D


A. Grass Field

思路: 签到, 4 4 4 个方块总数为 0 0 0 不推,总数为 4 4 4 至少 2 2 2 次,其余情况都是 1 1 1 次。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
void solve(){
    int sum=0;
    for(int i=1;i<=4;i++){
        int x;
        cin>>x;
        sum+=x;
    }
    if(sum==0)cout<<0<<endl;
    else if(sum==4)cout<<2<<endl;
    else cout<<1<<endl;
    return ;
}
signed main(){
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}

B. Permutation

思路: 贪心做法,显然让 d = 2 d=2 d=2 时造成的代价是最大的,剩下的就是模拟存储过程,从 1 1 1 开始枚举其 2 2 2 的幂次倍放入容器,枚举过的数跳过。最后将容器 vector 输出即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 2e5+10;
bool ok[N];
void solve(){
   memset(ok,false,sizeof ok);
   int n;
   cin>>n;
   vector<int>vec;
   for(int i=1;i<=n;i++){
       if(!ok[i]){
           int num=i;
           vec.push_back(i);
           ok[i]=true;
           while(num*2<=n&&!ok[num*2]){
               num=num*2;
               ok[num]=true;
               vec.push_back(num);
           }
       }
   }
   cout<<2<<endl;
   for(auto x:vec)cout<<x<<' ';
   cout<<endl;
}
signed main(){
   int t=1;
   cin>>t;
   while(t--){
       solve();
   }
}

C. Schedule Management

思路: 每个任务都有一个固定的熟练工人完成仅需 1s ,其余工人完成需要 2s 。让我们合理分配工人使得所有工作全部完成的时间最小。首先我们将每个工人能够 熟练完成 的任务统计起来。如果时间 Ti 比当前工人 i i i 拥有 熟练工作 少的话,那么工人 i i i 最好的策略就是全部做自己的 熟练工作 。否则如果当时间 Ti 比当前工人 i i i 拥有 熟练工作 大的话,那么工人 i i i 所能做的最大工作量是 i + ( T i − i ) / 2 i+(Ti-i)/2 i+(Tii)/2 。显然,如果时间固定,那么所有工人的总工作量是固定的。并且时间的多少具有 单调性 :时间越少所有工人总共能完成工作量越少,时间越多所有工人总共能完成工作量越多。 那么我们可以二分 c h e c k check check Ti 的大小,找到最小的 Ti 使得所有工人的总工作量 达标 ,即比 m 大。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 2e5+10;
int a[N];
int n,m;
bool check(int mid){
    int sum=0;
    for(int i=1;i<=n;i++){
        if(a[i]<=mid){
            sum+=a[i];
            sum+=(mid-a[i])/2;
        }
        else{
            sum+=mid;
        }
    }
    if(sum>=m)return true;
    else return false;
}
void solve(){
    mp.clear();
    cin>>n>>m;
    for(int i=1;i<=n;i++)a[i]=0;
    for(int i=1;i<=m;i++){
        int x;
        cin>>x;
        a[x]++;
    }
    sort(a+1,a+1+n);
    int l=0,r=m*2;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    cout<<l<<endl;
}   
signed main(){
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}

D. Permutation Restoration

思路: 给定一组 b b b 数组, b b b 数组中每个 b i b_i bi 是通过 每个下标 i i i a i a_i ai 下取整所获得。让我们恢复 a a a 数组,且 a a a 数组 一定是一个排列 。首先我们得到每个 a i a_i ai 的取值范围,他是一个区间。如果 b i b_i bi 0 0 0 那么显然 a i a_i ai ∈ \in [ [ [ a i a_i ai + 1 , n ] +1,n] +1,n] ,如果 b i b_i bi ! = 0 !=0 !=0,那么区间下界是 ( i / (i/ (i/ ( b i + 1 ) ) + 1 (b_i+1))+1 (bi+1))+1 , 上界是 i / b i i/b_i i/bi 所以 a i a_i ai ∈ \in [ ( i / [(i/ [(i/ ( b i + 1 ) ) + 1 , i / b i ] (b_i+1))+1,i/b_i] (bi+1))+1,i/bi] , 那么我们的 a i a_i ai 取值区间全部可以获得,并且这些区间 必定存在一种组合可以构造出一种排列 。显然,如果存在多个区间左端点取值为 1 1 1 ,那么我们将 区间右端点最小的区间隶属的 a i a_i ai 赋值为 1 1 1 是最贪心的选择,因为剩下同样左端点为 1 1 1 的区间 拥有更多赋值的选择 。那么做法呼之欲出,我们将所有区间按照左端点排序,用 优先队列 1 1 1 关键字存储区间右端点大小,第 2 2 2 关键字存储该区间隶属的 a i a_i ai 。每次赋值找到 优先队列中最坏的区间 并赋值即可,最终结果一定是最优的,如果最终结果不是排列,那么原数组 a a a 必定不是排列,又因为题目保证了 a a a 是一个排列, 那么最终构造的一定是一个排列

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 5e5+10;
typedef pair<int,int> PII;
struct Node{
    int l,r;
    int id;
    bool operator<(const Node &W)const{
        return l<W.l;
    }
}nodes[N];
int a[N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(x==0){
            nodes[i]={i+1,n,i};
        }
        else{
            int l2=i/x;
            int l1=i/(x+1)+1;
            nodes[i]={l1,l2,i};
        }
    }
    sort(nodes+1,nodes+1+n);
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    int cur = 0;
    for(int i=1;i<=n;i++){//枚举1-n的分配
        while(cur+1<=n&&nodes[cur+1].l==i){
            heap.push({nodes[++cur].r,nodes[cur].id});
        }
        a[heap.top().second]=i;
        heap.pop();
    }
    for(int i=1;i<=n;i++)cout<<a[i]<<' ';
    cout<<endl;
}   
signed main(){
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值