比赛链接:https://atcoder.jp/contests/abc310
比赛时间:2023年7月15日 20:00-21:40
A题:Order Something Else
标签:模拟
题意:给定
n
n
n个商品的价格
d
i
d_i
di元,现在推出一个饮料,原价
p
p
p元,如果买一个商品再买这个饮料只要
q
q
q元,求买这个饮料最少花多少钱。
题解:拿商品中的最低价格加上打折后饮料价格
q
q
q,和原价饮料价格
p
p
p进行对比,取最小值。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, p, q, d, mi = 1e9;
cin >> n >> p >> q;
for (int i = 1; i <= n; i++) {
cin >> d;
mi = min(mi, d);
}
cout << min(mi + q, p);
return 0;
}
B题:Strictly Superior
标签:枚举、模拟
题意:给定
n
n
n个产品,第
i
i
i个产品
p
i
p_i
pi元,且有
c
i
c_i
ci个功能
f
i
,
k
f_{i,k}
fi,k(
1
<
=
k
<
=
c
i
1<=k<=c_i
1<=k<=ci)。题目求有没有以下所以条件的情况出现(
1
<
=
i
,
j
<
=
n
1<=i,j<=n
1<=i,j<=n):
- p i > = p j p_i>=p_j pi>=pj
- 第 j j j个产品有第 i i i个产品的所有功能
- 要么 p i > p j p_i>p_j pi>pj或者 第 j j j个产品功能比第 i i i个产品的功能至少多一个
题解:题意有点坑,第三个条件满足其中一个就可以了。解法就是按题目要求模拟一下,在
p
i
>
=
p
j
p_i>=p_j
pi>=pj的情况下,去检测下第
j
j
j个产品功能有没有完全覆盖第
i
i
i个产品,并计数一下多的功能数。
代码:
#include <bits/stdc++.h>
using namespace std;
int p[105], f[105][105];
int main() {
bool ans = false;
int n, m, c, x;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> p[i] >> c;
for (int j = 1; j <= c; j++) {
cin >> x;
f[i][x] = 1;
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) continue;
if (p[j] <= p[i]) {
int cnt = 0;
bool flag = 1;
for (int k = 1; k <= m; k++) {
if (f[i][k] && !f[j][k]) {
flag = 0;
break;
}
else if (!f[i][k] && f[j][k]) {
cnt++;
}
}
if (flag == 1 && (cnt > 0 || p[j] < p[i])) {
ans = true;
break;
}
}
}
}
if (ans) cout << "Yes";
else cout << "No";
return 0;
}
C题:Reversible
标签:
S
T
L
STL
STL、
m
a
p
map
map
题意:给定
n
n
n个字符串,每个字符串可以翻转,如果两个字符串中其中一个翻转之后和另一个相同,认为这两个字符串也相同(比如
a
b
c
abc
abc和
c
b
a
cba
cba),题目求不同的字符串个数。
题解:用
m
a
p
map
map去标记下每个字符串的原串和翻转串,先检测一下,如果没有在
m
a
p
map
map中出现过,那就是新串,计数加一。
代码:
#include <bits/stdc++.h>
using namespace std;
map<string, int> m;
int main() {
int n, ans = 0;
string s;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s;
if (!m[s]) ans++;
m[s]++;
reverse(s.begin(), s.end());
m[s]++;
}
cout << ans << endl;
return 0;
}
D题:Peaceful Teams
标签:深搜
d
f
s
dfs
dfs、状压
d
p
dp
dp
题意:给定
n
n
n个运动员要分成
t
t
t只队伍(每只队伍至少
1
1
1人),并且给定
m
m
m个矛盾关系
a
i
a_i
ai运动员和
b
i
b_i
bi运动员,分成的队伍中两两运动员之间不能有矛盾,求满足条件的方法数有多少种。
题解:
n
<
=
10
n<=10
n<=10,考虑直接暴力搜索,暴力搜索的过程中需要考虑把第
i
i
i个人是分到新的一只队伍里面还是放在原来的前
m
x
mx
mx只队伍里面,通过这样可以降低时间复杂度,不然如果选择把每个人往
1
−
t
1-t
1−t只队伍里面放一边,时间复杂度太高了。最后把第
n
n
n个人处理完之后,检测一下是否有矛盾冲突的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
int n, t, m, a[50], b[50], vis[50], ans = 0;
void dfs(int k, int mx) {
if (k == n + 1) {
if (mx != t) return ;
for (int i = 1; i <= m; i++) {
if (vis[a[i]] == vis[b[i]]) return ;
}
ans++;
return;
}
for (int i = 1; i <= mx + 1; i++) {
vis[k] = i;
dfs(k + 1, max(i, mx));
vis[k] = 0;
}
}
int main() {
cin >> n >> t >> m;
for (int i = 1; i <= m; i++)
cin >> a[i] >> b[i];
dfs(1, 0);
cout << ans;
return 0;
}
E题:NAND repeatedly
标签:动态规划
题意:给定一个长度为
n
n
n的
01
01
01字符串
A
i
A_i
Ai,给定规则:
0
⊼
0
=
1
,
0
⊼
1
=
1
,
1
⊼
0
=
1
,
1
⊼
1
=
0
0⊼0=1,0⊼1=1,1⊼0=1,1⊼1=0
0⊼0=1,0⊼1=1,1⊼0=1,1⊼1=0。
求
∑
i
=
1
n
∑
j
=
i
n
f
(
i
,
j
)
\sum_{i=1}^n \sum_{j=i}^n f(i,j)
∑i=1n∑j=inf(i,j)(
1
<
=
i
<
=
j
<
=
n
1<=i<=j<=n
1<=i<=j<=n),
f
(
i
,
j
)
=
{
A
i
(
i
=
j
)
f
(
i
,
j
−
1
)
⊼
A
j
(
i
<
j
)
f(i,j)=\left\{\begin{matrix} A _ i&(i=j)\\ f(i,j-1)\barwedge A _ j\quad&(i\lt j) \end{matrix}\right.
f(i,j)={Aif(i,j−1)⊼Aj(i=j)(i<j)。
题解:显然我们可以通过
O
(
n
2
)
O(n^2)
O(n2)时间复杂度完成这道题要求,但是
n
<
=
1
0
6
n<=10^6
n<=106会超时。
d
p
[
i
]
[
0
/
1
]
dp[i][0/1]
dp[i][0/1]:前
i
i
i个数字累计
n
a
n
d
(
⊼
)
nand(⊼)
nand(⊼)为
0
/
1
0/1
0/1的方案数。分以下两种情况考虑:
- 当前数字是 0 0 0, d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况可以从前面 i − 1 i-1 i−1累计是 0 0 0和 1 1 1的情况转移过来,因为当前数字是 0 0 0,不管和 0 0 0和 1 1 1 n a n d ( ⊼ ) nand(⊼) nand(⊼)都是 1 1 1; d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况初始化成 1 1 1。
- 当前数字是 1 1 1, d p [ i ] [ 1 ] dp[i][1] dp[i][1]累计是 1 1 1的情况只能从前面 i − 1 i-1 i−1累计是 0 0 0的情况转移过来,并且计数增加 1 1 1(算上自己本身的),因为 1 ⊼ 1 = 0 1⊼1=0 1⊼1=0; d p [ i ] [ 0 ] dp[i][0] dp[i][0]累计是 0 0 0的情况从前面 i − 1 i-1 i−1累计是 1 1 1的情况转移过来。
最后把每个位置的
d
p
[
i
]
[
1
]
dp[i][1]
dp[i][1]累加一下即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
ll dp[N][2];
int main() {
ll n, ans = 0;
string s;
cin >> n >> s;
for (int i = 1; i <= n; i++) {
if (s[i-1] == '0') {
dp[i][1] = dp[i-1][0] + dp[i-1][1];
dp[i][0] = 1;
} else {
dp[i][1] = dp[i-1][0] + 1;
dp[i][0] = dp[i-1][1];
}
ans += dp[i][1];
}
cout << ans << endl;
return 0;
}