Codeforces Round 515 (Div. 3)

目录

A. Vova and Train

B. Heaters

C. Books Queries

D. Boxes Packing

E. Binary Numbers AND Sum

F. Yet another 2D Walking


A. Vova and Train

求区间重点额数量,由于数量具有前缀和效应所以我们考虑直接使用前缀和即可

void solve(){
    
    cin>>L>>v>>l>>r;
    int ans = L/v -(r/v-(l-1)/v);
    cout << ans << endl;
    return ;
}

B. Heaters

简单的线段覆盖问题,按照左端点排序,在满足可以覆盖左端点的同时选择最靠右边的线段即可(简单小贪心)

vector<PII> seg;
bool cmp(PII a,PII b){
	if(a.first==b.first) return a.second>b.second;
	return a.first<b.first;
}
void solve(){
    
    cin>>n>>r;
    for(int i=1;i<=n;i++){
    	int x; cin>>x;
    	if(x) seg.push_back({i-r+1,i+r-1});
    }
    sort(seg.begin(),seg.end(),cmp);
    int ed = 0;
    int ans = 0;
    for(int i=0;i<seg.size();i++){
    	int j = i;
    	int last = ed;
    	if(seg[i].first>last+1) break;
    	while(j<seg.size() and seg[j].first<=last+1) ed = max(ed,seg[j].second),j++;
    	j--;
    	i=j;
    	ans ++ ;
    	if(ed>=n) break;
    }
    cout << (ed>=n ? ans : -1) << endl;
    return ;
}

C. Books Queries

左右插数,考虑使用的对左右的数用正数和负数来区分即可,如果查询的数是左右两边注意减去0所占据的位置

int idxl,idxr;
void solve(){
    
    cin>>n;
    while(n--){
    	char op; int x; cin>>op>>x;
    	if(op=='?'){
    		int t = pos[x];
    		if(t>0) cout << min(idxr-t,t-idxl-1) << endl;
    		else cout << min(idxr-t-1,t-idxl) << endl;
    		
    	}
    	else{
    		if(op=='L') cnt[--idxl]=x,pos[x]=idxl;
    		else cnt[++idxr]=x,pos[x]=idxr;
    	}
    	
    }
    return ;
}

D. Boxes Packing

注意题目意思,其实是丢弃前缀,题目明显的具有二分性质,所以可以考虑从什么位置开始处理

,为了便于处理是否是被装在盒子里,我们可以直接用数组来表示盒子即可

int a[N],b[N];
 
bool check(int St){
	for(int i=1;i<=m;i++) b[i]=k;
	int cnt=0,j=1;
	for(int i=St;i<=n;i++){
		if(a[i]<=b[j]){
			b[j]-=a[i];
		}
		else{
			j++;
			if(j>m) return false;
			b[j]-=a[i];
		}
	}
	return true;
}
 
void solve(){
	
    cin>>n>>m>>k;
	for(int i=1;i<=n;i++) cin>>a[i];    
	int l=1,r=n+1;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<n-l+1<<endl;
    return ;
}

E. Binary Numbers AND Sum

前缀和思路,对于每一次除以之后的操作其实就是整个大于等于这个位置的前缀的数和这个位置数的操作,所以可以直接对其做一个前缀和即可

int pre[N];
LL qmi(LL a,LL b,LL p){
	LL res =1;
	while(b){
		if(b&1) res=res*a%p;
		a=a*a%p;
		b>>=1;
	}
	return res;
}
 
void solve(){
    
    string a,b; cin>>n>>m>>a>>b;
    a=' '+a,b=' '+b;
    for(int i=1;i<=m;i++){
    	pre[i]=pre[i-1]+(b[i]-'0');
    }
    LL ans = 0;
    for(int i=n,j=m,cnt=0;i>=1 and j>=1;i--,j--,cnt++){
    	if(a[i]=='1') ans +=(LL)qmi(2,cnt,mod)*pre[j]%mod;
    	ans %= mod;
    }
    cout << ans << endl;
    return ;
}

F. Yet another 2D Walking

几何中的dp,我们考虑如果是在同一个大小状态之下,我们可以按照从最左下到最右上的顺序或者是反之,(中间点就在两个点的曼哈顿距离中)最后一定是在这两个位置中的一个取转移下一个位置,所以不妨直接对这两个状态来进行转移

struct code{
	int x,y,S;
	bool operator<(const code&t)const{
		if(S!=t.S) return S<t.S;
		if(x!=t.x) return x<t.x;
		return y>t.y;
	}
}e[N];
 
// 一个倒着的L的形状
 
int dp[N][2];
 
PII w[N];
 
int get(int i,int j){
	auto [x1,y1,_]=e[i];
	auto [x2,y2,__]=e[j];
	return abs(x1-x2)+abs(y1-y2);
}
 
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++){
    	int x,y; cin>>x>>y;
    	e[i]={x,y,max(x,y)};
    }
    
    sort(e+1,e+1+n);
 
    int cnt=0;
    
    for(int i=1;i<=n;i++){
    	int j=i;
    	while(j+1<=n && e[i].S==e[j+1].S) j++;
    	w[++cnt]={i,j};// 表示左右边界
    	i=j;
    }
   
    for(int i=1;i<=cnt;i++){
    	auto [l,r]=w[i];
    	auto [ll,rr]=w[i-1];
    	dp[i][0]=min(dp[i-1][1]+get(rr,r),dp[i-1][0]+get(ll,r))+get(l,r);// 表示当前在左上
    	dp[i][1]=min(dp[i-1][1]+get(rr,l),dp[i-1][0]+get(ll,l))+get(l,r);// 表示当前在右下
    }
    cout<<min(dp[cnt][1],dp[cnt][0])<<endl;
    return ;
}

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值