Educational Codeforces Round 109 (Rated for Div. 2) 个人题解

好毒的场啊,2万人只有1000左右过了3题+……

A. Potion-making

没想到被A题卡了20分钟,甚至还wa了两次(掉分绝对原因),虽然仍然是个水题,但好好分析一下引以为戒吧……

题意

给定一个百分比k,然后从0开始制药。每次可以加一滴原料或者加一滴水,问最少加几滴东西,可以让药的原料浓度为k%.(k为整数)

分析

知道应该是简单的数学题,但开局懒了不想推,于是暴力枚举,结果double不熟练一直出不了……最后还是老老实实用结论。

找到k和100的最大公因数g,然后我们就可以以g为单位,替换掉百分比里以1%为单位的计算方式,也就是1滴的贡献将变为g分之一。比如,100和6的最大公因子是2,我们就可以“一滴当两滴”,只需要50滴中有3滴原料,就满足条件了。

故答案为 100 ÷ g c d ( k , 100 ) 100÷gcd(k,100) 100÷gcd(k,100).

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
//#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const double eps = 1e-4;
signed main()
{
//    IOS;
    int t;
    cin >> t;
    while(t--)
    {
    	int k;
    	cin >> k;
    	cout << 100 / __gcd(100, k) << endl;
	}
    return 0;
}

B. Permutation Sort

题意

给定一个数组,每次操作可以将一段连续子序列排成有序,但选取的子序列不能是整个原数组,问最少操作几次让数组有序。

分析

由于目标是整个数组有序,而我们又不能选取整个数组,那么贪心地选,我们每次操作都选取 n − 1 n-1 n1个元素(要么不选第一个,要么不选最后一个)

继续分析,问题就变简单了:

如果数组本来就有序,那就不操作了;

  1. 如果第一个元素和最后一个元素本来就是最大/最小的元素,那么只需要排中间 n − 2 n-2 n2个元素一次。

  2. 如果最小元素在第一个,最大元素不在最后一个,那么最大元素一定在中间 n − 2 n-2 n2个元素之中,我们将后 n − 1 n-1 n1个元素排一下就可以了,操作一次。(最小元素不在第一个,最大元素在最后一个同理)

  3. 如果最小元素在最后,最大元素在第一个,那么它们2个都无法一次到达应该到的位置。先由一次操作选取前 n − 1 n-1 n1个,把最大元素放到中间来,再由一次操作选取后 n − 1 n-1 n1个把最小元素放到中间,同时把最大元素放到最后一个,最后一次操作再把最小元素放到第一个,总共三次操作。

  4. 剩下的情况就是:最小元素和最大元素都不在自己的位置,但也没有出现3.中的情况。这说明最小元素和最大元素都在中间。由于一次操作不能同时覆盖第一个位置后最后一个位置,我们操作2次即可。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 55;
int a[maxn];
int n;
bool sorted()
{
	fors(i, 1, n - 1){
		if(a[i] > a[i + 1]){
			return 0;
		}
	}
	return 1;
}
signed main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
    	cin >> n;
    	int mn = inf, mx = -1;
    	fors(i, 1, n) cin >> a[i], mn = min(mn, a[i]), mx = max(mx, a[i]);
    	if(sorted()){
    		cout << 0 << endl;
    		continue;
		}
		else{
			if(a[1] == mn || a[n] == mx){
				cout << 1 << endl;
			}
			else if(a[1] == mx && a[n] == mn){
				cout << 3 << endl;
			}
			else cout << 2 << endl;
		}
	}
    return 0;
}

C. Robot Collisions

题意

描述起来有点复杂呀,看开头的链接吧QAQ。

分析

分析特点:假如一个robot的初始坐标是1,另一个的坐标是3,那么不管他们开始的方向怎么样,墙的坐标怎么样,由于碰到墙会反弹,最后一定会相撞(想一想为什么 --lrj);进一步思考,如果不考虑其他robot,有一对robot坐标都为奇数,那么它们一定会相撞。

相应的,如果一对robot坐标都为偶数,那么它们也一定会相撞。

而如果一个坐标是奇数,另一个是偶数,那么它们无论如何也不会相撞,最多只会擦肩而过(一个从坐标a移动到坐标b,另一个从坐标b移动到坐标a)。

因此,我们可以将所有机器人按初始坐标分组,奇数为一组,偶数为一组。不同组的机器人之间没有任何关系。

接着,对于同一组的机器人,很容易知道:相向而行的机器人无论如何都会比同向行进的机器人先相撞。相邻的机器人,如果左边的是往右走,右边的是往左走,他们就一定相撞。把所有相邻的"RL"全部消掉,剩下的机器人的行动方向一定是"LL…LR…RR",然后,对于剩下的所有向左走的机器人,前两个会首先相撞,然后是第3、4个相撞,以此类推.最后至多剩下一个往左走的机器人。右边同理。如果向左、向右都剩下了一个机器人,那么这两个机器人也可以相撞(它们行进的路径上没有其他机器人了,最后一定相遇)。

代码


#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
int n, m;
const int maxn = 3e5 + 10;
struct node{
    int x, id;
    char c;
    bool operator<(const node& b)const{
        return x < b.x;
    }
};
deque<node> a;
deque<node> b;
int ans[maxn];
void operate(deque<node> &u){
            sort(u.begin(), u.end());
        // 先去除所有相邻RL的.
        stack<node> q;
        for(int i = 0; i < u.size(); ++i){
            if(u[i].c == 'R'){
                q.push(u[i]);
                continue;
            }
            if(q.empty()) continue;
            ans[q.top().id] = ans[u[i].id] = (u[i].x - q.top().x) / 2;
            q.pop();
        }
        deque<node> tmp;
        for(int i = 0; i < u.size(); ++i){
            if(ans[u[i].id] == -1){
                tmp.push_back(u[i]);
            }
        }
        u = tmp;
        while(u.size() > 1){
            node p1 = u.back(); u.pop_back();
            node p2 = u.back(); u.pop_back();
            if(p1.c == p2.c && p1.c == 'R'){
                ans[p1.id] = ans[p2.id] = ((m - p1.x) * 2 + p1.x - p2.x) / 2;
            }
            else{
                u.push_back(p2);
                u.push_back(p1);
                break;
            }
        }
        while(u.size() > 1){
            node p1 = u.front(); u.pop_front();
            node p2 = u.front(); u.pop_front();
            if(p1.c == p2.c && p1.c == 'L'){
                ans[p1.id] = ans[p2.id] = (p2.x + p1.x) / 2;
            }
            else{
                u.push_front(p2);
                u.push_front(p1);
                break;
            }
        }
        if(u.size() == 2){
            ans[u.front().id] = ans[u.back().id] = (2 * u.front().x + 2 * (m - u.back().x) + abs(u.back().x - u.front().x)) / 2;;
        }
        u.clear();
}
node A[maxn];
signed main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n >> m;
        node tmp;
        fors(i, 1, n){
            cin >> A[i].x;
            A[i].id = i;
            ans[i] = -1;
        }
        fors(i, 1, n){
            cin >> A[i].c;
            if(A[i].x & 1) a.pb(A[i]);
            else b.pb(A[i]);
        }
        operate(a), operate(b);
        fors(i, 1, n){
            cout << ans[i] << ' ';
        }
        cout << endl;
    }
    return 0;
}

D. Armchairs

震惊!竟然是最小费用最大流模板题!
然而依旧可以用二维dp做出

题意

给定一个01串,要把所有的1填到0上面去,同一个0只能填一个1. 每次填数的花费为0和1
这两个位置的差值。问要把所有的1填过去,最小花费是多少。

分析

最小费用最大流我不会

直接讲dp思路吧,有点毒……这题很容易误导人往贪心想,唉。

d p [ i ] [ j ] dp[i][j] dp[i][j]表示对前 i i i个1,把他们放到前 j j j个0的最小花费。 d p dp dp数组初始化为 i n f inf inf. 然后,很显然地所有 d p [ 0 ] [ i ] dp[0][i] dp[0][i]是0. 接下来是状态转移:

对于 i , j i,j i,j,我们看第 i i i个1到底该放哪。选择只有2个:要么放第 j j j个,要么放到前 j − 1 j-1 j1个位置的某一个。前 j − 1 j-1 j1看成一个位置是因为我们已经知道了 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1]嘛。 状态转移方程:

d p [ i ] [ j ] = m i n ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j − 1 ] + ∣ p o s 0 [ j ] − p o s 1 [ i ] ∣ dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+|pos0[j]-pos1[i]| dp[i][j]=min(dp[i][j1],dp[i1][j1]+pos0[j]pos1[i]

式中 p o s 0 [ j ] pos0[j] pos0[j]表示第 j j j个0出现的位置, p o s 1 [ i ] pos1[i] pos1[i]表示第 i i i个1出现的位置。

因为经过初始化,所以当 i > j i>j i>j时, d p dp dp值无法更新,肯定是 i n f inf inf

那么答案显然是 d p [ n u m 1 ] [ n u m 0 ] dp[num1][num0] dp[num1][num0]了。

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
// #define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
// #define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
int n;
const int maxn = 5005;
int a[maxn]; // 1
int b[maxn]; // 0
int dp[maxn][maxn];
signed main()
{
	IOS;
	// int t;
	// cin >> t;
	// while(t--)
	// {
		int x;
		int pa = 1, pb = 1;
		cin >> n;
		fors(i, 1, n){
			cin >> x;
			if(x) a[pa++] = i;
			else b[pb++] = i;
		}
		memset(dp, 0x3f, sizeof(dp));
		fors(i, 0, pb) dp[0][i] = 0;
		fors(i, 1, pa){
			fors(j, 1, pb){
				dp[i][j] = min(dp[i][j - 1], dp[i - 1][j - 1] + abs(a[i] - b[j]));
			}
		}
		cout << dp[pa][pb] << endl;
	// }
	return 0;
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值