Educational Codeforces Round 131 A - D

A. Grass Field

https://codeforces.com/contest/1701/problem/A

标签

简单构造

题意

给定一个 2 * 2 的 01 矩阵,每次操作可以将一行和一列置零。问至少操作几次,才能使矩阵均为0。

思路

见代码

代码

image-20220709131126740

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		int sum=0;
		FOR(i,1,4){
			int x;cin>>x;sum+=x;
		}
		if(sum==0)cout<<0<<endl;
		if(sum>=1 and sum<=3)cout<<1<<endl;
		if(sum==4)cout<<2<<endl;
	}
	return 0;
}

B. Permutation

https://codeforces.com/contest/1701/problem/B

标签

贪心, 排列

题意

对于一个正整数 d, 定义长度为 n 的排列 p 的花费是使得 p[i] * d = p[i + 1] 成立的下标 i 的数量.

给定 n, 对于长度为 n 的排列 p, 找到有最大花费的 d 和这个排列.

如果有多个答案, 输出任意一个.

思路

贪心.

在排列中, 使得后一项是前一项的 2 倍, 即 d = 2, 可以获得最大花费.

例如 n = 6, p={1, 2, 4, 3, 6, 5};

代码

image-20220709132552709

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;

vector<int> a;
array<int,200007> vst;

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		a.clear();
		vst.fill(0);
		int n;cin>>n;
		FOR(i,1,n){
			if(vst[i]) continue;
			for(int j=i;j<=n and !vst[j];j*=2){
				vst[j]=1;
				a.push_back(j);
			}
		}
		cout<<2<<endl;
		for(auto i:a) cout<<i<<" ";
		cout<<endl;
	}
	return 0;
}

C. Schedule Management

https://codeforces.com/contest/1701/problem/C

标签

二分

题意

有 n 人要完成 m 项任务, n <= m, 每一项任务都有一个精通的人,精通的人完成它需要 1 h, 其他人完成需要 2 h.

问至少需要多少小时, 才能将全部任务完成.

思路

二分答案, 见代码注释.

代码

AC

image-20220709135124065

image-20220709135133688

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;

#define int long long
const int N=2e5+7;
int n,m;
int task[N];

//二分的特征是假设已经知道答案, check函数根据答案反推出这个答案成不成立
bool check(int t){
	int sum=m;//注意sum多次减去数可能会造成int负数溢出
	FOR(i,1,n){
		if(task[i]>=t*1){//这个工人全部用于完成精通任务
			sum-=t;//完成了t个精通任务
		}
		else{//这个工人要同时完成精通和非精通任务
			sum-=task[i];//完成了所有他的精通任务
			sum-=(t-task[i])/2;//完成了 剩余时间/2 取整的非精通任务
		}
	}
	if(sum<=0) return true;//完成了所有任务
	else return false;
}

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		cin>>n>>m;
		memset(task,0,sizeof task);
		FOR(i,1,m){
			int x;cin>>x;
			task[x]++;
		}
		int l=1,r=1e9;//r=2*m也可以,复杂度相同
		while(l<r){//整数二分
			int mid=(l+r)/2;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		cout<<r<<endl;
	}
	return 0;
}

注意 sum 多次减去数可能会造成 int 负数溢出.

image-20220709135206808

TLE
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;

int task[200007];
int stat[200007];

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		memset(task,0,sizeof task);
		int n,m; cin>>n>>m;
		FOR(i,1,n) stat[i]=1;
		FOR(i,1,m){
			int x;cin>>x;
			task[x]++;
		}
		int sum=m, ans=0;
		while(sum>0){
			ans++;
			FOR(i,1,n){
				if(sum==0) break;
				if(task[i]>0){
					task[i]--;
					stat[i]++;
					sum--;
				}
			}
			FOR(i,1,n){
				if(sum==0) break;
				if(stat[i]>ans or task[i]>0) continue;
                int max0=0,pos;
                FOR(i,1,n){
                    if(max0<task[i]) max0=task[i],pos=i;
                }
                task[pos]--;
                stat[i]+=2;
                sum--;
			}
		}
		FOR(i,1,n) ans=max(ans,stat[i]);
		cout<<ans-1<<endl;
	}
	return 0;
}

D. Permutation Restoration

https://codeforces.com/contest/1701/problem/D

标签

取整不等式, 贪心, 排列

题意

有一个排列 a 和数组 b, 定义 $ b_i = \lfloor \frac{i}{a_i} \rfloor$.

现在给定 b, 求出任意一个符合条件的 a.

题目保证有解.

思路

参考

由 于   b i = ⌊ i a i ⌋ 由于\ b_i = \lfloor \frac{i}{a_i} \rfloor  bi=aii

即   b i ≤ i a i < b i + 1 即\ b_i \leq \frac{i}{a_i} \lt b_i+1  biaii<bi+1

所 以   i b i + 1 < a i ≤ i b i 所以\ \frac{i}{b_i+1} \lt a_i \leq \frac{i}{b_i}  bi+1i<aibii

image-20220709213536648

代码

AC

image-20220709213605420

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define ROF(i,a,b) for(int i=(a);i>=(b);--i)
#define PII pair<int,int>
using namespace std;

void solve(){
    int n; cin>>n;
    vector<PII> v[n+7];
    int ans[n+7];
    FOR(i,1,n){
    	int b,l,r;cin>>b;
        l=i/(b+1)+1;
        if(b==0) r=n;
        else r=i/b;
        v[l].push_back({r, i});
    }
    set<PII> s;
    FOR(i,1,n){
    	for(auto it: v[i]) s.insert(it);
    	auto it=s.begin();
    	ans[(*it).second]=i;
    	s.erase(s.begin());
    }
    FOR(i,1,n) cout<<ans[i]<<" ";
    cout<<endl;
}

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		solve();
	}
	return 0;
}
TLE
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
using namespace std;

struct node{
	int a,b,l,r,dif,index;
};//a[i], b[i], l<=a[i]<=b[i], r-l, i

bool cmp1(const node &x,const node &y){
	//if(x.dif==y.dif) return x.index<y.index;
	return x.r<y.r;
}

bool cmp2(const node &x,const node &y){
	return x.index<y.index;
}

signed main(){
	cin.tie(0)->sync_with_stdio(0);
	int T;cin>>T;
	while(T--){
		int n;cin>>n;
		vector<node> p(n+7);
		vector<int> vst(n+7,0);
		FOR(i,1,n){
			int b,l,r;cin>>b;
			l=i/(b+1)+1;
			if(b==0) r=n;
			else r=i/b;
			p[i]={0,b,l,r,r-l,i};
			//printf("l=%d, r=%d\n",l,r);
		}
		sort(p.begin()+1,p.begin()+n+1,cmp1);//O(nlogn)
		FOR(i,1,n){
			FOR(j,p[i].l,p[i].r){//O(n^2)
				if(!vst[j]){
					vst[j]=1;
					p[i].a=j;
					break;
				}
			}
		}
		sort(p.begin()+1,p.begin()+n+1,cmp2);
		FOR(i,1,n){
			cout<<p[i].a<<" ";
		}
		cout<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值