Codeforces Educational Round 84 题解

也许更好的阅读体验

CF1327A Sum of Odd Integers

我才不会告诉你们这道题我错了3次才AC

首先我们要明白一个事实:奇数个奇数的和是奇数,偶数个奇数的和是偶数。如果我们要把 n n n 拆成 k k k 个奇数(先不考虑拆成不同的奇数), n n n k k k 的奇偶性必须相同。

于是我们得到:

条件1: n m o d    2 = k m o d    2 n \mod 2 = k \mod 2 nmod2=kmod2

接下来我们考虑拆成 k k k不同的奇数需要满足什么条件。

其实只要满足 n n n 大于等于前 k k k 个奇数的总和就可以了。(因为我们总可以把最大的奇数不断增加直至总和为 n n n

举个栗子: n = 21 , k = 4 n=21,k=4 n=21,k=4 时,首先前4个奇数分别是 1 , 3 , 5 , 7 1,3,5,7 1,3,5,7。因为 21 > 1 + 3 + 5 + 7 21>1+3+5+7 21>1+3+5+7,所以我们可以把 7 7 7 增加至 12 12 12,这样就满足条件了。

而前 k k k 个奇数的和是 k 2 k^2 k2,于是我们得到:

条件2: n ≥ k 2 n \ge k^2 nk2

综上,AC代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
	//ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while(t--)
	{
		int n,k;
		cin >> n >> k;
		if(n % 2 == k % 2 && n >= k * k)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	return 0;
}

CF1327B Princesses and Princes

刚开始确实没有想到这道题模拟就可以了。

我们首先按照国王的规则包办婚姻,然后看看有没有剩男剩女未能配对的王子和公主,把它们配对就OK了。如果所有公主都嫁出去了,答案就是OPTIMAL

但是这样有一个问题:题目里说了这样一句话(还特别加粗)

Note that this kingdom should not be present in the daughter’s list.

后来我想了想发现这是废话!!!如果有未能配对的王子和公主,那么这个王子一定不是公主喜欢的人。

反证法:假如这个王子出现在了公主喜欢的人的列表中,且这个公主没有嫁出去,这个王子也没有娶任何一个公主,那么这个公主和王子就一定可以配对,矛盾。

所以题目这句话有点坑

最后我们的代码就很简洁了:

#include<bits/stdc++.h>
#define endl '\n'//一般输出规模超过10^5最好用'\n'换行
using namespace std;
const int maxn = 100010;
bool used[maxn], choosed[maxn];
//分别为王子和公主

int main()
{
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while(t--)
	{
		int n;
		cin >> n;
		fill(used + 1, used + n + 1, false);
        fill(choosed + 1, choosed + n + 1, false);
		for(int i = 1; i <= n; i++)
		{
			int k;
			cin >> k;
			bool flag = false;
			for(int j = 1; j <= k; j++)
			{
				int x;
				cin >> x;
				if(!flag && !used[x])
				{
					used[x] = true;
					choosed[i] = true;
					flag = true;
				}
			}
		}
		bool flag = false;
		for(int i = 1; i <= n; i++)
			if(!used[i])
			{
				for(int j = 1; j <= n; j++)
					if(!choosed[j])
					{
						cout << "IMPROVE" << endl << j << ' ' << i << endl;
						flag = true;
						break;
					}
				if(flag)
					break;
			}
		if(!flag)
			cout << "OPTIMAL" << endl;
	}
	return 0;
}

时间复杂度是 O ( n ) O(n) O(n)

因为只要有一个没配对的王子,就必然有一个没配对的公主。

吐槽下洛谷的题意翻译,叫王子和公主多好

CF1327C Game with Chips

这里我要感谢下比赛时候的弹窗:

We don’t have to minimize the number of operations in problem C.

所以其实这道题的 k , s x , s y , f x , f y k,sx,sy,fx,fy k,sx,sy,fx,fy 都用不到!(惊不惊喜意不意外)

由于最大移动次数限制是 2 n m 2nm 2nm,所以我们可以把整个棋盘全部走一遍。

我的做法是这样的:
首先先从右上角出发,不断向下,走到底再向左走一步,不断向上,走到顶再向左走一步,不断向下……一直走到左下角/左上角。
然后从左下角/左上角出发,与刚才的做法类似,一直走到最右端。
(读者可根据代码理解)

把整个棋盘全部走一遍之后,所有的chip一定能够经过目标。

这是因为我们的操作实际上相当于把所有的chip都利用墙壁堆到了左上角或左下角,然后再带着所有的chip遍历棋盘。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n, m, tmp
    cin >> n >> m >> tmp;
    for(int i = 1; i <= 4 * k; i++)
    	cin >> tmp;
    //大大简化了空间复杂度
    string ans = "";
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j < n; j++)
            if((m - i) % 2 == 0)
                ans += 'D';
            else
                ans += 'U';
        if(i != m)
            ans += 'L';
    }
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j < n; j++)
            if(i % 2 == 0)
                ans += 'D';
            else
                ans += 'U';
        if(i != m)
            ans += 'R';
    }
    cout << ans.size() << endl << ans << endl;
    return 0;
}

时间复杂度 O ( n × m ) O(n \times m) O(n×m),空间复杂度 O ( 1 ) O(1) O(1)

CF1327E Count The Blocks

这题其实就是个乘法原理的计算。

不难想到,一个block要么出现在两边,要么出现在中间,分别计算答案即可。

a n s i ans_i ansi 表示长为 i i i 的block的个数。

首先 a n s n = 10 ans_n = 10 ansn=10;(也就是 000 … 0 ,   111 … 1 ,   222 … 2 000\dots0,\ 111\dots1,\ 222\dots2 0000, 1111, 2222 一直到   999 … 9 \ 999\dots9  9999

然后,如果一个长为 i ( i < n ) i(i<n) i(i<n) 的block出现在两边,方案总数是 10 × 9 × 1 0 n − i − 1 × 2 10 \times 9 \times 10^{n-i-1} \times 2 10×9×10ni1×2
解释: 10 10 10(block本身有10种可能) × \times × 9 9 9(block旁边的数不能与block本身的取值相同) × \times × 1 0 n − i − 1 10^{n-i-1} 10ni1(剩下的数没有限制) × \times × 2 2 2(有两边)。

如果这个block出现在中间,方案总数是 10 × 9 2 × 1 0 n − i − 2 × ( n − i − 1 ) 10 \times 9^2 \times 10^{n-i-2} \times (n-i-1) 10×92×10ni2×(ni1)
解释: 10 10 10(block本身有10种可能) × \times × 9 2 9^2 92(block两边的数不能与block本身的取值相同) × \times × 1 0 n − i − 2 10^{n-i-2} 10ni2(剩下的数没有限制) × \times × ( n − i − 1 ) (n-i-1) (ni1)(中间有 n − i − 1 n-i-1 ni1 个block可以放置的位置)。

但是注意:当 i = n − 1 i=n-1 i=n1 时,这个block不可能出现在中间,所以我们要特判一下。
由于要大量用到 10 10 10 的幂,所以我们可以预处理一下降低时间复杂度。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const long long mod = 998244353;
long long n;
const int maxn = 200010;
long long pow10[maxn], ans[maxn];
int main()
{
	cin >> n;
	
	pow10[0] = 1;
	for(int i = 1; i <= n; i++)
		pow10[i] = pow10[i - 1] * 10 % mod;
	
	ans[n] = 10;
	ans[n - 1] = ans[n] * 2 * 9;
	for(int i = n - 2; i > 0; i--)
	{
		ans[i] = (ans[i] + 10 * 9 * pow10[n - i - 1] % mod * 2) % mod;
		ans[i] = (ans[i] + 10 * 9 * 9 * pow10[n - i - 2] % mod * (n - i - 1) % mod) % mod;
	}
	
	for(int i = 1; i <= n; i++)
		cout << ans[i] << ' ';
	cout << endl;
	
	return 0;
}

时间复杂度 O ( n ) O(n) O(n)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值