Codeforces #206 Div 2 题解

本文分享了作者在 CodeForces 平台上解决四道算法题的经历,包括数字根、公共交通票价优化、机器人取物策略及字符串游戏等题目,并提供了详细的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

鉴于本人最近智商和代码能力有明显下降趋势(年纪大了,没办法),准备刷CF保健康。

昨天选了第一版最后一个比赛,#206的div2 (怕div1 太难,做不出来哭)。

花了点时间,做了4题,D题不会(最后憋不住,看题解,结果看了也不会,而且看rng58的代码也看不明白哭,太弱了)

---------------------------------------------------我是分割线-----------------------------------------------

A . Vasya and Digital Root

题意
构造一个整数x,把x的数码累加和不断迭代直到这个值小于10,作为x的根r。现在给你r和x的位数k,要你构造出满足条件的x。

思路
x > 0 时,假设 d = x%9 ,如果 d = 0 ,则r 为9 ,其他的时候为d。证明很简单,把x拆成a_i*10^i的形式,数码和,提一个9出来就可以。
r = 0 时, x 一定是0。
所以构造的时候构造 9000..00r 这种数就可以了,r=0的时候特判一下就可以了。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
 
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;


int main(){
	int k,d;
	cin >> k >> d;
	if(d==0){
		if(k==1) cout << 0 << endl;
		else cout << "No solution" << endl;
	}	    
	else {
		if(k==1) cout << d << endl;
		else{
			int i;
			cout << 9;
			FU(i,k-2) cout << 0;
			if(d) cout << d << endl;
			else cout << 9 << endl;
		}
	}
    return 0;
}
----------------------------------------------------------我还是分割线--------------------------------------

B. Vasya and Public Transport
题意
坐巴士和电车,有4种票
1 单程票,只能坐某个车1次
2 单车票,可以坐某个车无限次次
3 单类票,可以坐所有的巴士或者所有的电车无限次次
4 全票,可以无限制坐无限次。
给你要坐的巴士和电车的线路和次数,问你最小花费。
思路
简单贪心。
首先全票肯定可以全部搞定。
针对某一类,最多是一张单类票。
对于某一单类的每个线路,贪心计算,如果单程票*次数 > 单车票,那就选单车票,否则选单程票。
最后看这个价格是否超过单类票,取小的。
两类的最小花费之和如果小于全票,那就取这个花费即可。
代码写的比较挫,c+v了一下。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
 
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
#define N 1000

int main(){
	int ans,s1,s2,n,m,i,j,a,b,c,d,t;
	cin >>  a >> b >> c >> d;
	cin >> n >> m;
	
	ans = d;

	s1 = 0;
	FU(i,n){
		cin >> t;
		if(t*a > b) s1 += b;
		else s1 += t*a; 
	}   
	if(s1 > c) s1 = c;
	s2 = 0;
	FU(i,m){
		cin >> t;
		if(t*a > b) s2 += b;
		else s2 += t*a; 
	}
	if(s2 > c) s2 = c;
	if(ans > s1+s2) ans = s1+s2;
	cout << ans << endl; 
    return 0;
}
----------------------------------------------------------我仍然是分割线-------------------------------------
C.
题意
给你一排N个物品组成的双端队列,机器人去取,单位耗费从左取的是L,从右取是R。
如果连续从左取,附加耗费是 QL;连续从右取,附加耗费是QR。
问你取完的最小耗费。
思路
首先和括号匹配一样,不会出现RL这种取法,所以一定是从某一点分开,左边的全部从左取,
右边的全部从右取。显然交替取的代价比连续取低,所以某一点分开,基础代价是
左边重量和*L+右边重量和*R ,
额外的耗费,令 t = 右边次数 - 左边次数。
如果t > 1 ,那么加上 (t-1) * QR;
如果t< -1 那么加上 (-t-1) * QL。
综上,预处理左边重量累加和和右边重量累积和,然后扫一遍,计算每个分割点的搬运代价,
取极小即可。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
 
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<n;i++)
#define FD(i,n) for(i=n-1;i>=0;i--)
#define EPS 1e-8
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;

#define N 100011
int a[N];
int Left[N];
int Right[N];

const int INF = 0x3f3f3f3f;
int main(){
	int i,j,n,L,R,QL,QR,s=0,k;
	int t,ans = INF;
	//freopen("355c.in","r",stdin);
	
	cin >> n >> L >> R >> QL >> QR;
	for(i=1;i<=n;i++) cin >> a[i];
	
	for(i=1;i<=n;i++) Left[i] = Left[i-1] + a[i];
	
	for(i=n-1;i>=0;i--) Right[i] = Right[i+1] + a[i+1];
	
	for(i=0;i<=n;i++) {
		t = Left[i] * L + Right[i]*R;
		k = n - i*2;		
		if(k>1) t += QR*(k-1);
		else if(k<-1)  t += QL*(-k-1);
		if(t < ans) ans = t;
	}
	//FU(i,n+1) cout << Left[i] << ',';
	//cout << endl;
	//FU(i,n+1) cout << Right[i] << ',';
	//cout << endl;
	
	cout << ans << endl;
    return 0;
}

奇怪的是,我的INF设成0x33333333居然会WA,设成0x3f3f3f3f就AC了。而我拿那个WA的数据本地跑
又不会WA。。。不知道为什么 抓狂

----------------------------------------------------------我继续是分割线---------------------------------------
D.

题意
一个n*n(n<=20)的矩阵,每个元素是一个小写英文字母,从左上到右下,只能向下和向右走,每次走一步。
两人聪明人轮流走,其路径构成的字符串中如果字符a多,那么第一个人赢;
如果字符b多,那么第二人赢;相同则平局。问最后的结果。

思路
直觉告诉我DP,而且n只有20,估计是状压,因为是博弈,显然是按对角线进行dp的。但是不会表示状态。。。,就放弃去做E了。
做完E,想了半天也没头绪,最后没憋住,看了一下官方题解,居然没看懂。。。跑去看大神的代码,div2居然没人过!!!
又跑去div1看rng58的代码,果然神代码,没看明白什么意思。。。我怀疑是不是我看错题了,但是看了几遍觉得没错。下午问胡大,
胡大说以前做过,也没看明白。。。留着以后再做吧。

----------------------------------------------------------我最后是分割线----------------------------------------
题意
给n个数ai,和k,可以把ai减去不超过k,问所有数最大公约数是多少?
思路
假设最大公约数是d,那么 ai % d <= k。
令 m = min{ai},显然 d <= m
如果 ai % m <= k ,那么m即所求。
a %m <= m-1 , 那么 m-1 <= k 。 所以 当 m <= k+1 时, m即所求。
那么 m > k+1 时了?
因为 d最小只要取k+1,那么肯定满足条件,所以 d 只能取 [k+1,m]之间的数。
枚举d,从m到k+1,检验是不是所有的ai%d <= k 就可以找出d。
但是直接做会TLE(开始就是这么挂掉的。。。)。
我们可以看出 [d,d+k],[2d,2d+k]是不重叠的,所以我们可以统计[d,d+k],[2d,2d+k],...[id,id+k],
i = max{ai}/d。看这些区间一共覆盖了多少个ai,如果是n个的话,那么就一定是解。
所以hash一下,先预处理区间中ai的个数,然后枚举1到i,统计一下就可以了(自己脑子抽了一下,想了半天才想到hash,果然是老了)。
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <vector>
#include <string>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <list>
#include <map>
#include <set>
#include <cstdio>
#include <deque>
#include <cassert>
#include <iomanip>
using namespace std;
 
#define PB push_back
#define MP make_pair
#define FU(i,n) for(i=0;i<(n);i++)
#define FD(i,n) for(i=(n)-1;i>=0;i--)
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f; 
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef pair<int,int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 2e6+2;

int a[N];


int main(){
	ios::sync_with_stdio(false);	    
	int n,k,d,min=INF,max=0,i,j,c,t;
	cin >> n >> k;
	FU(i,n){
		cin >> t;
		a[t]++;
		if(t>max) max = t;
		if(t<min) min = t;
	}
	if(min <= k+1) {
		cout << min << endl;
		return 0;
	}
	for(i=1;i<N;i++) a[i] += a[i-1];
	for(d=min;d>=k+1;d--){
		c = 0;
		for(i=1;i<=max/d;i++) c += a[i*d+k] - a[i*d - 1];
		if(c == n) {
			cout << d << endl;
			return 0;
		}
	}
	
	
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值