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+(Ti−i)/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();
}
}