Codeforces #704(div 2) A~D题解

11 篇文章 0 订阅
8 篇文章 0 订阅

A. Three swimmers

题目链接

题意:
给四个整数 p , a , b , c p,a,b,c p,a,b,c。其中 a , b , c a,b,c a,b,c分别表示三个游泳者到达泳池边的时间点,比如,第一个游泳者到达泳池边的时间就是 0 , a , 2 a , 3 a , … 0,a,2a,3a,\dots 0,a,2a,3a,。p表示的是一个人来到泳池边的时间点,问这个人在泳池边要等多久才能见到第一个到达泳池边的游泳者。

题解:
直接找 a , b , c a,b,c a,b,c的大于等于p的最小倍数即可。注意数据范围比较大,保守起见开了 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned long long

具体细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;

int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int t;
    cin >> t;
    while (t--) {
        ll p, a, b, c;
        cin >> p >> a >> b >> c;
        ll newa = (p + a - 1) / a * a;
        ll newb = (p + b - 1) / b * b;
        ll newc = (p + c - 1) / c * c;
        cout << min(newa, min(newb, newc)) - p << endl;
    }
    return 0;
}

B. Card Deck

题目链接

题意:
给了我们一个长度为n的排列p,p的第一个元素是底,最后一个元素是顶,我们每次可以从顶取出一些元素放在一个新牌组上,原来在p中当顶的元素成为新牌组中的底,按这种方式取出所有p的元素,让我们找出一个排列使得 ∑ i = 1 n n n − i ⋅ p i \sum_{i=1}^n n^{n-i}·p_i i=1nnnipi的值最大。

题解:
看起来比较棘手,不过我们分析题目所给的样例能够很快发现,其实就是从后往前找到当前剩余元素中最大的数的位置 i i i,然后把从 i i i到结尾的所有元素取出放入新牌组即可。每次按这种方式取,直到取完。

具体实现见代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;

int p[MAXN];
int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int t;
    cin >> t;
    while (t--) {
        int n;
        int maxx = -1, id = 0;
        set<int> vis;
        vector<int> ans;
        cin >> n;
        for (int i = 0; i < n; i++) {
        	cin >> p[i];
        	if (p[i] > maxx) {
        		maxx = p[i];
        		id = i;
        	}
        }
        for (int i = n - 1; i >= 0; i--) {
        	ans.emplace_back(p[i]); // 从顶依次加入元素
        	vis.insert(p[i]); // 判断元素是否被取过
        	if (p[i] == maxx) { // 如果当前元素是最大值,倒序输出
                int len = ans.size();
                for (int j = len - 1; j >= 0; j--) {
                    cout << ans[j] << " ";
                }
                ans.clear();
        		while (vis.count(maxx)) { // 找到当前剩余元素中的最大值
        			maxx--;
        		}
        	}
        }
        cout << endl;
    }
    return 0;
}

C. Maximum width

题目链接

题意:
给我们一个长度为n的字符串S和一个长度为m的字符串T,让我们找到一个长度为m的严格上升的序列p,使得p中元素在S串中对应的字符串正好是T串,同时定义p序列的宽度是p中元素 p i + 1 − p i p_{i+1} - p_i pi+1pi的最大值,问我们这个宽度最大可以是多少?

题解:
这道题目,由于求的是相邻字符对应位置的差值的最大值,那么为了使这个差值最大,我们容易想到相邻字符一个取最左的坐标,一个取最右的坐标,因此我们可以对T串前后扫两边,从前扫,每次找到当前T串字符在S串的最左的位置坐标;从后扫,每次找到当前T串字符在S串的最右的位置坐标。最后,扫描一遍T串,找到相邻字符的坐标差值最大值。

具体细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;

ll nowr[MAXN], nowl[MAXN];
int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int m, n;
	cin >> n >> m;
	string s, t;
	cin >> s >> t;
	ll sleft = 0;
	for (int i = 0; i < m; i++) {
		while (s[sleft] != t[i] && sleft <= n - 1) { // 找到当前t[i]在s串中的最左坐标
			sleft += 1;
		}
		nowl[i] = sleft++;
	}
	ll sright = n - 1;
	for (int i = m - 1; i >= 0 && sright >= 0; i--) { // 找到当前t[i]在s串中的最右坐标
		while (s[sright] != t[i] && sright >= 0) {
			sright -= 1;
		}
		nowr[i] = sright--;
	}
	ll ans = 0;
	for (int i = 1; i < m; i++) {
		ans = max(ans, nowr[i] - nowl[i - 1]);
	}
	cout << ans << endl;
    return 0;
}

D. Genius’s Gambit

题目链接

这题FST比例就离谱。感觉大部分都是错在一些特判上。

题意:
给我们3个整数 a , b , k a,b,k a,b,k,让我们判断能不能构造出两个二进制数 x x x y y y,满足:

  1. x ≥ y x≥y xy
  2. x x x y y y中都有 a a a个0和 b b b个1
  3. x − y x-y xy这个二进制数中有 k k k个1

题解:
经过手推几个样例,能够发现当 k > a + b − 2 k>a+b-2 k>a+b2时不能构造这样的二进制数。不过,这样其实是不对的,当样例是0 1 0的时候,我们可以构造 x = 1   y = 1 x=1\ y=1 x=1 y=1这样两个二进制数,因此我们要对 b = 1 , k = 0 b=1,k=0 b=1,k=0的时候进行特判。我这里一般的构造方法就是,根据 a a a k k k的大小关系,分别进行两种不同的构造。

a ≥ k a≥k ak时,对于 x 和 y x和y xy,先以 b − 1 b-1 b1个1开头。然后由于最后要有k个1,因此,在 x x x中,我以倒数第 k k k个位置作为分界线,给倒数第 k k k个位置设为1,其他位置设为0;在 y y y中,我把最后一个位置设为1,其他剩余位置设为0,这样 x − y x-y xy就一定有k个1,且满足其他条件。

a < k a<k a<k时,我把 x x x的最后 a a a个位置设为0,其他位置都设为1。而 y y y中,与x不同之处就在就在 a + b − k a+b-k a+bk这个位置,在 x x x中是1,但是在 y y y中我设置为0。

按照以上方式写出的构造程序,看起来是对的,不过,少了 a = 0 a = 0 a=0时的特判。我们发现当 a = 0 , k = 0 a=0,k=0 a=0,k=0时,其实是可以构造出全部是1的两个二进制数。

具体细节见代码:

#include <bits/stdc++.h>
using namespace std;

int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int a, b, k;
	cin >> a >> b >> k;
	if (b == 1) { // 特判b = 1
        if (k == 0) {
            cout << "Yes" << endl;
            cout << 1;
            for (int i = 1; i <= a; ++i) {
            	cout << 0;
            }
            cout << endl;
            cout << 1;
            for (int i = 1; i <= a; ++i) {
            	cout << 0;
            }
            cout << endl;
        }
        else {
        	cout << "No" << endl;
        }
        return 0;
    }
    if (a == 0) { // 特判a = 0
        if (k == 0) {
            cout << "Yes" << endl;
            for (int i = 1; i <= b; ++i) {
            	cout << 1;
            }
            cout << endl;
            for (int i = 1; i <= b; ++i) {
            	cout << 1;
            }
            cout << endl;
        }
        else {
        	cout << "No" << endl;
        }
        return 0;
    }
	if (k > a + b - 2) {
		cout << "No" << endl;
	}
	else if (a >= k) {
		cout << "Yes" << endl;
		for (int i = 1; i < b; i++) {
			cout << 1;
		}
		for (int i = 1; i <= a - k; i++) {
			cout << 0;
		}
		cout << 1;
		for (int i = 1; i <= k; i++) {
			cout << 0;
		}
		cout << endl;
		for (int i = 1; i < b; i++) {
			cout << 1;
		}
		for (int i = 1; i <= a; i++) {
			cout << 0;
		}
		cout << 1 << endl;
	}
	else {
		cout << "Yes" << endl;
		for (int i = 1; i < a + b - k; i++) {
			cout << 1;
		}
		cout << 1;
		for (int i = 1; i <= k - a; i++) {
			cout << 1;
		}
		for (int i = 1; i <= a; i++) {
			cout << 0;
		}
		cout << endl;
		for (int i = 1; i < a + b - k; i++) {
			cout << 1;
		}
		cout << 0;
		for (int i = 1; i <= k - a; i++) {
			cout << 1;
		}
		for (int i = 1; i < a; i++) {
			cout << 0;
		}
		cout << 1 << endl;
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值