AtCoder Beginner Contest 167(补题)
Posted 佐鼬Jun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 167(补题)相关的知识,希望对你有一定的参考价值。
C - Skill Up
题意:
高桥对于 M M M种算法的基础是0,现在有N本书,每本书对这M种算法都有加成,第 i i i本书,售价 C i C_i Ci元,对于算法的提升是 A i , 1 A_{i,1} Ai,1 A i , 2 A_{i,2} Ai,2 A i , 3 A_{i,3} Ai,3… A i , M A_{i,M} Ai,M,现在要求使高桥对于M种算法的基础超过X,问最少花多少钱。
思路:
N和M的数据范围只有12,可以直接暴力dfs搜索,注意加一点剪枝,就可以,这里我写的搜索参数
dfs(int
u
u
u, int
c
o
s
t
cost
cost, int
s
u
m
[
]
sum[]
sum[]) 意思使,选择了第u个书,现在花费使cost,
s
u
m
[
]
sum[]
sum[]代表对于M种算法,每个的基础值,搜所有情况,然后取最小值即可,不符合要求的话,就输出-1
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
#define inf 0x3f3f3f3f
int a[N][N];
int n, m, x;
int c[N];
int vis[N];
int sum[N];
int res;
void dfs(int u, int cost, int sum[]) {
if (cost >= res) {
return;
}
bool flag = 1;
for (int j = 1; j <= m; j++) {
if (sum[j] < x) {
flag = 0;
break;
}
}
if (flag) {
res = cost;
return;
}
for (int i = u + 1; i <= n; i++) {
if (!vis[i]) {
vis[i] = 1;
for (int j = 1; j <= m; j++) {
sum[j] += a[i][j];
}
dfs(i, cost + c[i], sum);
for (int j = 1; j <= m; j++) {
sum[j] -= a[i][j];
}
vis[i] = 0;
}
}
}
int main() {
cin >> n >> m >> x;
for (int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
for (int j = 1; j <= m; j++) {
scanf("%d", &a[i][j]);
}
}
res = inf;
for (int i = 1; i <= n; i++) {
int cost = c[i];
memset(sum, 0, sizeof(sum));
for (int j = 1; j <= m; j++) {
sum[j] += a[i][j];
}
vis[i] = 1;
dfs(i, cost, sum);
}
if (res == inf)
puts("-1");
else {
cout << res << endl;
}
}
D - Teleporter
题意:
现在给你 n n n个数,即n个城市, a i a_i ai代表城市 i i i可以传送 a i a_i ai号城市,高桥现在要从1号城市走,问传送 k k k次,最终传送到哪个城市
思路:
标记环路,一旦进入了环路,就会循环不停地走,找从1开始走的路径,一旦进了环路,标记出环路,把走到环路后,剩下的次数对
k
k
k取模,看能到哪个点。如果还没走到环,就停止了,就直接输出就行。
先找路径,发现有循环回来了,就在用一个数组来存环路
找路径,就直接从1号点,往后走就行,如果走回之前走过的点,就说明有环路了,再记录环路。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define ll long long
int a[N];
vector<int> path, cycle;
map<int, int> m;
ll n, k;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1;; i = a[i]) {
if (!m[a[i]]) {
path.push_back(a[i]);
m[a[i]] = 1;
} else {
bool flag = 0;
for (int j : path) {
if (j == a[i]) flag = 1;
if (flag) cycle.push_back(j);
}
break;
}
}
if (k <= path.size()) {
cout << path[k - 1] << endl;
} else {
k -= path.size();
k %= cycle.size();
int cnt = (k - 1 + cycle.size()) % cycle.size();
cout << cycle[cnt] << endl;
}
}
E - Colorful Blocks
题意:
有 n n n个球,横着排列,有 m m m种颜色(可以不全用),最多能有 k k k对相邻的球颜色相同,问有多少种涂色方案
思路:
隔板法:
n
n
n个球,就有
n
+
1
n+1
n+1个隔板,除了最两边的隔板外,每删除一个隔板,就相当于把相邻的球弄为一种颜色,最多有
k
k
k个相邻,说明最多可以删除
k
k
k个隔板,所以就是然后同一个隔板内部的可以视为一个整体,相当于是一种颜色,第一个隔板内部有
m
m
m种选择,第二个有
m
−
1
m-1
m−1个选择,第三个也有
m
−
1
m-1
m−1个选择,直到最后一个。
所以推出来的公式就是:
∑
i
=
0
k
\\sum \\limits_{i=0} ^{k}
i=0∑k
C
n
−
1
i
C^i_{n-1}
Cn−1i
⋅
·
⋅
(
m
−
1
)
n
−
1
−
i
(m-1)^{n-1-i}
(m−1)n−1−i
⋅
m
·m
⋅m
在答案中取模,并且记得开long long 这个题就算结束。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const ll mod = 998244353;
ll fact[N], infact[N];
ll n, m, k;
ll qmi(ll a, ll k, ll p) {
int res = 1;
while (k) {
if (k & 1) res = (ll)res * a % p;
a = (ll)a * a % p;
k >>= 1;
}
return res;
}
void init() {
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i++) {
fact[i] = (ll)fact[i - 1] * i % mod;
infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
}
int main() {
init();
cin >> n >> m >> k;
ll res = 0;
for (int i = 0; i <= k; i++) {
int a = n - 1, b = i;
res = (ll)res + m * fact[a] % mod * infact[b] % mod * infact[a - b] %mod * qmi(m - 1, n - 1 - i, mod) % mod;
res = res % mod;
}
cout << res << endl;
}
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激
以上是关于AtCoder Beginner Contest 167(补题)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解