Daily Practice: Codeforces Round #816 (Div. 2)

因为第二天要去学校所以这一场没有打,,VP*n

A. Crossmarket

现有两人,其中一人要从左下角走到右上角,另一人要从左上角走到右下角,左下到右上的人每走一格会在当前格制作一个传送门,当某一人在一个有传送门的格子时,可以传送到另一个具有传送门的格子,每走一格需要一个单位的能量,问两人最少一共需要多少能量。

思路:可以制作传送门的人很显然只能一格一格走到终点,另一人尽可能传送最长的距离,计算一下即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n,m;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>m;
		if(n==1&&m==1){
			std::cout<<0<<'\n';
			continue;
		}
		std::cout<<n+m-2+std::min(n,m)<<'\n';
	}
	return 0;
}

B. Beautiful Array

定义一个数组的beauty值为数组中每个数除以k向下取整的值之和,现在给出数组中元素个数,k的值,beauty值,所有元素之和,能否构造一个数组满足条件。

思路:我们可以尽量使构造方法简单。即beauty值集中在一个数。若是总和除以k小于b,那一定无法构造;若除以k大于b,我们可以让其中一个贡献beauty值的数为(b+1)*k-1,尽可能使用总和,其他的给每一个剩余位置赋值k-1(如果可以的话),若全部赋完值s还有剩余的数,那就不可能存在满足条件的数组。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t;
ll n,k,b,s;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>k>>b>>s;
		if(s/k<b){
			std::cout<<-1<<'\n';
			continue;
		}
		std::vector<ll>ans(n+1,0);
		if(s/k==b){
			std::cout<<s;
			for(int i=1;i<n;i++){
				std::cout<<' '<<0;
			}
			std::cout<<'\n';
			continue;
		}
		ans[1]=(b+1)*k-1;
		s-=ans[1];
		for(int i=2;i<=n;i++){
			if(s>=k-1) ans[i]=k-1,s-=(k-1);
			else if(s) ans[i]=s,s=0;
			else if(s==0) ans[i]=0;
		}
		if(s){
			std::cout<<-1<<'\n';
			continue;
		}
		for(int i=1;i<=n;i++){
			std::cout<<ans[i]<<" \n"[i==n];
		}
	}
	return 0;
}

 os:没开ll WA了一发

C. Monoblock

 一个序列可以根据相邻数字是否相同分段,现给出一个数组,每次修改其中一个值,对于每次修改,输出其所有子串的分段数和。

思路:因为所有的修改都是基于原数组的,所以一开始计算原数组的值是必要的。可以采用双指针的方式从后向前计算以i为开头的子串的值。对于每次修改,讨论会对答案造成影响的情况,若第i个值与i-1个不同,但是修改完成为相同的,那相应的值会-1,然后找到包含这个数的区间作相应的修改,即(n-x+1)*(x-1),相反情况则是加上这个数。对于i个i+1的讨论同理。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
ll n,m;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>n>>m;
	std::vector<ll>a(n+2,0),f(n+2,0);
	for(int i=1;i<=n;i++){
		std::cin>>a[i];
	}
	ll sum=0;
	for(int i=n;i>=1;i--){
		int j=i;
		while(j&&a[j-1]==a[i]) j--;
		f[i]=f[i+1]+n-i+1;
		sum+=f[i];
		for(int k=i-1;k>=j;k--){
			f[k]=f[k+1]+1,sum+=f[k];
		}
		i=j;
	}
	while(m--){
		ll x,y;
		std::cin>>x>>y;
		if(a[x]==y){
			std::cout<<sum<<'\n';
			continue;
		}
		if(y==a[x-1]&&a[x]!=a[x-1]) sum-=(n-x+1)*(x-1);
        if(y!=a[x-1]&&a[x]==a[x-1]) sum+=(n-x+1)*(x-1);
        if(y==a[x+1]&&a[x]!=a[x+1]) sum-=(n-x)*x;
        if(y!=a[x+1]&&a[x]==a[x+1]) sum+=(n-x)*x;
        std::cout<<sum<<'\n';
        a[x]=y;
	}
	return 0;
}

D. 2+ doors

 给出q个关系,对于每个关系给出x,y,v三个值,表示a[x]|a[y]=v,构造一个字典序最小的数组,满足给出的条件。

思路:实质就是对于二进制下的v按照它的0或1分配给两个数0或1因为要字典序最小,所以尽可能多的赋0。对于v的位是0的情况,那一定是两数该位都是0,若是1的情况,则一定是一个0一个1,x和y靠前的那个赋0。但是最后会出现一些矛盾,即0和1的位置,那就按照前面的赋值来决定该位的情况。注意x==y时直接等于v。

AC Code:

#include <bits/stdc++.h>

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

struct node{
	int x,v;
};

std::vector<node>vec[N];

signed main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>n>>m;
	for(int i=1;i<=m;i++){
		int a,b,c;
		std::cin>>a>>b>>c;
		vec[a].push_back({b,c});
		vec[b].push_back({a,c});
	}
	for(int i=1;i<=n;i++){
		ans[i]=(1<<30)-1;
		for(auto e:vec[i])
			ans[i]&=e.v;
		if(!vec[i].size()) ans[i]=0;
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<30;j++){
			if(ans[i]>>j&1){
				bool flag=false;
				for(auto e:vec[i])
					if(!(ans[e.x]>>j&1)||e.x==i)
						flag=true;
				if(!flag) ans[i]-=(1<<j);
			}
		}
	}
	for(int i=1;i<=n;i++){
		std::cout<<ans[i]<<' ';
	}
	std::cout<<'\n';
	return 0;
}

感觉这场CD还好?虽然没做出来。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值