Codeforces Round #515(div3)

A. Vova and Train

C++代码如下:

#include<iostream>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int L,v,l,r;
		cin>>L>>v>>l>>r;
		cout<<L/v-(r/v-(l-1)/v)<<endl;
	}
	return 0;
}

B. Heaters

题意:简化版:给定一些区间,问最少需要几个区间才能覆盖数组中的所有点

步骤:

1、对所有区间进行按左端点从小到大的排序,last表示上一次遍历的区间的最右端点,初始化为0

2、遍历区间,对所有区间左端点小于等于last+1的的区间,找出它们中右端点最大的一个,选择右端点最大的一个区间,更新last为这个最大的右端点

3、若找不到右端点最大的区间或者找到的最大的右端点都等于last,则退出循环

4、重复步骤2,直到last==n为止

最后,如果last!=n,输出-1,否则输出区间的个数ans

C++代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
typedef pair<int,int> PII;
PII s[N];
int a[N],cnt;
int main(){
	int n,r;
	cin>>n>>r;
	for(int i=1;i<=n;i++)cin>>a[i];
	int sum=0,ans=0;
	for(int i=1;i<=n;i++){
		if(a[i]==1){
            //所有区间都涵盖在1~n当中
			int L=max(i-r+1,1),R=min(i+r-1,n);
			s[cnt++]={L,R};
			sum++;
		}
	}
	sort(s,s+cnt);
	int last=0,j=0;
	while(last<n){
		int t=last;//t存储要找的最大的右端点
		while(j<cnt&&s[j].first<=last+1){
			t=max(t,s[j].second);
			j++;
		}
		if(t>last)last=t,ans++;//选择右端点最大的一个区间,ans++,last=t
		else break;
	}
	if(last!=n)cout<<-1<<endl;
	else cout<<ans<<endl;
	return 0;
}

C. Books Queries

题意:(简化版)往书架上放书,从中间开始放每次要么放在左边,要么放在右边(假设书架无限长),对于每次询问,L和R表示放书,?表示询问,问的是最少取下几本书才能让这本书在边缘,即问该书左边和右边的书的最小数min(左边书的数量,右边书的数量)

步骤:

1、设置一个长度为书架两倍的数组,2*N,从中间开始放书,hh=N,tt=N+1,放书时hh往左减,tt往右加,数组a[N]记录每本书放在书架上的位置

2、对于每次?询问图书b,输出min(a[b]-hh-1,tt-a[b]-1)即可

C++代码如下:

#include<iostream>
using namespace std;
const int N=200010;
int q[2*N],a[N];
int hh=N,tt=N+1;
int n;
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		char c;
		int b;
		cin>>c>>b;
		if(c=='L')q[hh--]=b,a[b]=hh+1;
		else if(c=='R')q[tt++]=b,a[b]=tt-1;
		else cout<<min(a[b]-hh-1,tt-a[b]-1)<<endl;
	}
	return 0;
}

D. Boxes Packing

题意:将物品放入盒子中,盒子的数量有限,所有盒子只能放编号连续的物品,问最多可以放下几个物品,很明显的二分

注意以下几点:

  • 如果当前方案合适,则从mid到n的所有物品都必须放得下
  • 如果遇到了一个物品大于盒子容量,直接返回false,不用看后面的,因为一定会导致放的物品不连续
  • 遍历物品时盒子不够了也返回false

C++代码如下:

#include<iostream>
using namespace std;
const int N=200010;
int a[N];
int n,m,k;
bool check(int mid){
	int cnt=1,remain=k,flag=0;
	for(int i=mid;i<=n;i++){
		if(a[i]<=remain)remain-=a[i];
		else{
			cnt++;
			remain=k;
            //如果当前物品大于盒子容量或者盒子不够了,返回false
			if(a[i]>k||cnt>m)return false;
			i--;
		}
	}
	return true;
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
	int l=0,r=n;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	if(l==n&&a[n]>k)cout<<0<<endl;
	else cout<<n-l+(l!=0)<<endl;
	return 0;
}

E. Binary Numbers AND Sum

步骤:用字符串存储a和b,ans存储答案

1、从前往后用前缀和处理b中出现的1的个数,cnt[i]=cnt[i-1]+(b[i]=='1')

2、从后往前用i枚举a的每一位,每次遇到‘1’(假设编号为i)就找该编号前面b中出现的1的个数,出现几个1就给ans加上几个当前位在a中的二进制权值,即2^(n-i-1)

3、枚举到n-i>m,则直接跳出循环

  • 计算的时候用快速幂,能降低时间复杂度

C++代码如下:

#include<iostream>
using namespace std;
const int N=200010,mod=998244353;
typedef long long LL;
int cnt[N];
int n,m,ans=0;
int qmi(int a,int k,int p){//快速幂求a^p%k的值 
	int res=1;
	while(k){
		if(k&1)res=(LL)res*a%mod;
		a=(LL)a*a%mod;
		k>>=1;
	}
	return res;
}
int main(){
	cin>>n>>m;
	string a,b;
	cin>>a>>b;
	for(int i=0;i<m;i++){
		if(i==0)cnt[i]=(b[i]=='1');
		else cnt[i]=cnt[i-1]+(b[i]=='1');
	}
	for(int i=n-1;i>=0;i--){
		if(n-i<=m){
			if(a[i]=='1'){
				ans=(LL)(ans+(LL)cnt[m-(n-i)]*qmi(2,n-i-1,mod)%mod)%mod;
			}
		}else break;
	}
	cout<<ans<<endl;
	return 0;
}

F. Yet another 2D Walking

还没写,最后一题也不一定会写,写了再更新hh

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值