Educational Codeforces Round 107 (Rated for Div. 2)
A(水题)
题目链接
⭐
题目:
有两个计票员,\(n\)个观众,每个观众可以按顺序投票,如下所示有三种票
- 1 代表支持
- 2 代表不支持
- 3 如果当前计票员收到的支持票数大于等于不支持票数,则投支持,反之不支持
求出支持票数的最大值
解析:
让一个计票员专门收反对票,另一个计票员收其他种类的票,很显然答案就是\(1\)与\(3\)的票数之和
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
int main() {
//FRE;
int T, n, t;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
int t1 = 0, t2 = 0;
while (n--) {
scanf("%d", &t);
if (t & 1) ++t1;
else ++t2;
}
printf("%d\n", t1);
}
}
B(GCD)
题目链接
⭐
题目:
给出\(a,b,c\)代表\(A,B,C\)三个数所代表的十进制位数,同时满足\(GCD(A,B)=C\),输出满足条件的\(A,B\)
解析:
由于\(A=A'C,B=B'C\)且\(A'\)与\(B'\)互质,考虑C为10的幂,可以很好的控制A与B的位数,那么任务就转变成了寻找位数分别为\(a-c+1\)与\(b-c+1\)且互质的\(A'\)与\(B'\),不难发现\(10^x与10^y+1\)一定互质(由于前者只能质因数分解成若干个2与5的幂次,而后者一定不能被2或5整除),那么问题迎刃而解
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
/*===========================================*/
ll ten[10];
int main() {
//FRE;
int T;
ten[1] = 1;
for (int i = 2; i < 10; ++i)
ten[i] = ten[i - 1] * 10;
scanf("%d", &T);
int a, b, c;
while (T--) {
scanf("%d%d%d", &a, &b, &c);
printf("%lld %lld\n", ten[a - c + 1] * ten[c], (ten[b - c + 1] + 1) * ten[c]);
}
}
C(思维)
题目链接
⭐⭐
题目:
给出一叠牌,从上到下给出每个牌的颜色,有\(m\)次询问,每次询问最上方颜色为\(t\)的牌的位置,输出,并把这张牌抽出放于牌顶
解析:
由于每次每次询问最上方的牌,并把它放在牌顶,所以只需要记录每种颜色最上方的牌,并在每次查询时,维护好这个颜色队列即可
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
const int maxn = 3e5 + 5;
int q[maxn];
int cnt = 0;
bool vis[maxn];
int pos[maxn];
int main() {
//FRE;
int n, m, t;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf("%d", &t);
if (!vis[t]) {
vis[t] = true;
q[cnt++] = t;
pos[t] = i;
}
}
while (m--) {
scanf("%d", &t);
printf("%d ", pos[t]);
int i = 0;
for (; q[i] != t; ++i)
++pos[q[i]];
for (; i > 0; --i)
q[i] = q[i - 1];
pos[t] = 1;
q[0] = t;
}
}
D(构造)
题目链接
⭐⭐
题目:
如果\(s_i=s_j(i<j)\),且\(s_{i+1}=s_{j+1}\),则花费加1,现在给出字符串长度,以及字符集大小,求出最小代价的字符串
解析:
可以尝试考虑重复构造代价为0的串,即时刻保证当前两位后缀从未在之前出现过,可以考虑这样的构造方法,每次从\(a\)开始枚举字符,先输出一个\(cur\),再输出\(cur\#\),\(cur\)代表当前字符,\(\#\)代表比\(cur\)大的字符,这样可以保证所有字符集合中所有两两组合都出现过
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/
int n, m, c;
void P(int i) {
printf("%c", i + 'a');
if (++c == n) exit(0);
}
int main() {
//FRE;
scanf("%d%d", &n, &m);
while (1) {
for (int i = 0; i < m; ++i) {
P(i);
for (int j = i + 1; j < m; ++j)
P(i), P(j);
}
}
}
E(dp+组合数学)
题目链接
⭐⭐⭐⭐
题目:
给出一个矩阵,\(o\)代表白块,\(*\)代表黑块,每个白块可以染成red与blue两种颜色,横排两个连续的红块可以防止一个多米诺牌,竖排两个连续的蓝块可以放置一个多米诺牌,多米诺牌不能重叠,每个白块必须被染色,问每种染色方案所能放置的最大多米诺牌数之和(取模\(998244353\))
解析:
-
考虑对于某一行连续的白块,定义\(dp[i]\)为前\(i\)个连续白块最多能放置的多米诺牌之和,那么对于\(dp[i+1]\)
- 如果第\(i+1\)个白块被染成蓝色,则此时剩余白块的贡献为\(dp[i]\)
- 如果第\(i+1\)个白块被染成红色
- 如果第\(i\)个白块被染成红色,则此时剩余\(i-1\)个白块的贡献为\(dp[i-1]\),最后两个红块对于整体的贡献为\(2^{i-1}\)
- 如果第\(i\)个白块被染成蓝色,则此时剩余白块的贡献为\(dp[i-1]\)
-
综上可以得到状态转移方程\(dp[i]=dp[i-1]+2*dp[i-2]+2^{i-2}\)
-
那么统计所有连续的白块行和白块列,利用\(dp\)可以\(O(1)\)求出这段白块行/列对于每种染色矩阵的贡献,因此假设这段白块长度为\(x\),答案加上\(dp[x]*2^{white-x}\)
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
/*===========================================*/
using namespace std;
const int maxn = 3e5 + 5, mod = 998244353.;
ll dp[maxn], two[maxn];
string e[maxn];
int main() {
IOS
two[0] = 1;
int n, m;
for (int i = 1; i < maxn; ++i)
two[i] = two[i - 1] * 2 % mod;
for (int i = 2; i < maxn; ++i)
dp[i] = (dp[i - 1] + 2 * dp[i - 2] % mod + two[i - 2]) % mod;
cin >> n >> m;
int end = max(n, m);
ll ret = 0, c;
int white = 0;
for (int i = 0; i < n; ++i) {
cin >> e[i];
for (auto& j : e[i])
white += j == 'o';
}
for (int i = 0; i < n; ++i) {
c = 0;
for (int j = 0; j < m; ++j) {
if (e[i][j] == 'o') ++c;
else if (c) {
ret = (ret + dp[c] * two[white - c]) % mod;
c = 0;
}
}
if (c)
ret = (ret + dp[c] * two[white - c]) % mod;
}
for (int j = 0; j < m; ++j) {
c = 0;
for (int i = 0; i < n; ++i) {
if (e[i][j] == 'o') ++c;
else if (c) {
ret = (ret + dp[c] * two[white - c]) % mod;
c = 0;
}
}
if (c)
ret = (ret + dp[c] * two[white - c]) % mod;
}
cout << ret;
}