Codeforces Round #802 (Div. 2)

期末复习一个月没敲代码了,暑假开始复健hhhh

A. Optimal Path

给出n*m个方格,按照题目所示标号,问从(1,1)到(n,m)所走的路径中,权值最小是多少(权值为路径上所有方格标号数字之和)。

思路:贪心,一定是先按行走再按列走权值最小。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e4+5;
int t,n,m;
ll a[N];

void init(){
	for(int i=1;i<=1e4;i++){
		a[i]=a[i-1]+i;
	}
}

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cin>>t;
	init();
	while(t--){
		std::cin>>n>>m;
		ll ans1=a[m];
		ll ans2=a[n]*m;
		std::cout<<ans1+ans2-m<<'\n';
	}
	return 0;
}

B. Palindromic Numbers

给出一个n位数,求一个相同位的数,使得这两个数相加是回文数。

思路:分类讨论,我们容易想到,9999是回文数,1111也是回文数,那么对于最高位是小于9的数,我们可以令相加所得的回文数为相同位数的9,这样模拟很容易;对于最高位是9的数,我们可以令所得的回文数为高一位的若干个1,模拟减法即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e4+5;
int t,n;
std::string x;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n>>x;
		int len=x.length();
		std::stack<int>sta;
		bool flag=false;
		if(x[0]=='9'){
			for(int i=len-1;i>=0;i--){
				if(x[i]<='1')
					if(!flag)
						sta.push(1-(x[i]-'0'));
					else{
						if(x[i]=='0')
							sta.push(0),flag=false;
						else{
							sta.push(10-(x[i]-'0'));
						}
					}
				else{
					if(!flag)
						sta.push(11-(x[i]-'0')),flag=true;
					else{
						sta.push(10-(x[i]-'0'));
					}
				}
			}
			while(!sta.empty()){
				std::cout<<sta.top();
				sta.pop();
			}
			std::cout<<'\n';
		}
		else{
			std::string s="";
			for(int i=0;i<len;i++){
				s+=(9-(x[i]-'0')+'0');
			}
			std::cout<<s<<'\n';
		}
	}
	return 0;
}

os:确实太长时间没练习了,思路慢写代码也慢。

C. Helping the Nature

给出一个数列,问最少经过几次操作使得数列中所有数均为0。操作分为三类:对于标号1~i的数均减一; 对于标号i~n的数均减一; 数列所有的数均加1。

思路:考虑差分。对于三种操作,第一种对应到差分数组就是dif[1]-1,dif[i+1]+1;第二种就是dif[i]-1,dif[n+1]+1;第三种就是dif[1]+1,dif[n+1]-1。所以对于dif数组小于0的,我们可以使用第一种操作,令小于0的变为0,同时对dif[1]进行修改;其他的dif数组中非0的可以使用其他两种操作使其为0,因为a[0]=0,而计算a[n]时与dif[n+1]没有关系,故保证可以这样操作。

#include <bits/stdc++.h>

typedef long long ll;
const int N=2e5+5;
ll t,n;
ll a[N],dif[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			dif[i]=a[i]-a[i-1];
		}
		ll ans=0;
		for(int i=2;i<=n;i++){
			if(dif[i]<0) dif[1]+=dif[i],ans-=dif[i],dif[i]=0;
		}
		for(int i=1;i<=n;i++){
			ans+=abs(dif[i]);
		}
		std::cout<<ans<<'\n';
	}
	return 0;
}

os:hpggtqllllll!!!

D. River Locks

 给出n个空间,每个空间可以盛v[i]的水,每个空间上方有个注水的管道,问最少开几个管道可以使得给出的时间内可以使所有空间都注满水,注意某个空间注满水后剩余的水会流向下一个空间,如图所示。

思路:首先有个前提条件我们应该知道,我们应该尽量开上游的管道,这样可以使得上游的水流到下游而不是直接注入河流造成浪费;这样开x个管道注满所有空间所需的时间是\sum v/x,我们容易想到二分答案得到结果。但是注意注满空间是有时间的下限的,即注满前i个空间所需的最短时间是前i个空间之和除以i,所以二分答案之前应该注意判断是否小于下限,若小于则直接输出-1。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=2e5+5;
ll n,q,x;
ll v[N],f[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cin>>n;
	ll max=-1;
	for(int i=1;i<=n;i++){
		std::cin>>v[i];
		f[i]=f[i-1]+v[i];
		max=std::max(max,(f[i]+i-1)/i);
	}
	std::cin>>q;
	while(q--){
		std::cin>>x;
		if(max>x){
			std::cout<<-1<<'\n';
			continue;
		}
		ll l=1,r=n;
		while(l<r){
			ll mid=l+r>>1;
			if (x*mid>=f[n]) r=mid;
            else l=mid+1;
		}
		std::cout<<l<<'\n';
	}
	return 0;
}

太久没打cf头脑都不灵活了,好在有同学这次带飞hhhhh(暑假应该大概可能也许会上青吧)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值