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 n≥k2
综上,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 000…0, 111…1, 222…2 一直到 999 … 9 \ 999\dots9 999…9)
然后,如果一个长为
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×10n−i−1×2。
解释:
10
10
10(block本身有10种可能)
×
\times
×
9
9
9(block旁边的数不能与block本身的取值相同)
×
\times
×
1
0
n
−
i
−
1
10^{n-i-1}
10n−i−1(剩下的数没有限制)
×
\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×10n−i−2×(n−i−1)。
解释:
10
10
10(block本身有10种可能)
×
\times
×
9
2
9^2
92(block两边的数不能与block本身的取值相同)
×
\times
×
1
0
n
−
i
−
2
10^{n-i-2}
10n−i−2(剩下的数没有限制)
×
\times
×
(
n
−
i
−
1
)
(n-i-1)
(n−i−1)(中间有
n
−
i
−
1
n-i-1
n−i−1 个block可以放置的位置)。
但是注意:当
i
=
n
−
1
i=n-1
i=n−1 时,这个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)。