LINE Verda Programming Contest(AtCoder Beginner Contest 263)A-F
LINE Verda Programming Contest(AtCoder Beginner Contest 263)
https://atcoder.jp/contests/abc263
G 待补
A - Full House
输入5个数,判断是否满足两个数相等,另外三个数相等
#include <bits/stdc++.h>
using namespace std;
int main () {
set<int> s;
map<int, int> mp;
int n = 5, x;
while (n --) {
cin >> x;
s.insert(x);
mp[x] ++;
}
if (mp.size() != 2) {
cout << "No";
return 0;
}
bool f1 = false, f2 = false;
for (auto i : mp) {
if (i.second == 2) f1 = true;
if (i.second == 3) f2 = true;
}
if (f1 && f2) {
cout << "Yes";
}
else cout << "No";
}
B - Ancestor
找爸爸:i的爸爸是pi,问n和1之间隔了几代
挨个找过去即可
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int a[N], n;
int main () {
cin >> n;
for (int i = 2; i <= n; i ++) cin >> a[i];
int ans = 0, x = n;
while (1) {
x = a[x];
ans ++;
if (x == 1) break;
}
cout << ans;
}
C - Monotonically Increasing
输出所有长度为n,可选数范围为1-m的严格上升序列
全排列 + 筛选
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int> a;
for (int i = 0; i < n; i++)
a.push_back(0);
for (int i = 0; i < m - n; i++)
a.push_back(1);
for (int i = 0; i < m; i++)
if (a[i] == 0)
cout << i + 1 << " ";
cout << endl;
while (next_permutation(a.begin(), a.end())) {
for (int i = 0; i < m; i++)
if (a[i] == 0)
cout << i + 1 << " ";
cout << endl;
}
}
//输出所有长度为2,数字范围在1~m的严格上升序列
D - Left Right Operation
题意
进行如下操作各一次:
- 把 \(a_1,a_2,...,a_x\) 全替换为 L;
- 把 \(a_{n-y+1},...,a_{n-1},a_n\) 全替换为 R;
\(0\leq x,y\leq n\)
问a的和最小为多少
分析
f1[i]表示 \(1\) ~ \(i\) 最小可能和,\(f2_i\) 表示 \(1\) ~ \(i\) 最小可能和
则答案在 \(f1_i+f2_{i+1}\) 中取(尽可能替换更多的,故枚举分界点)
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 5, inf = 1e18;
int n, a[N], l, r;
int f1[N], f2[N];
signed main () {
cin >> n >> l >> r;
for (int i = 0; i < n; i ++) cin >> a[i];
f1[0] = min (a[0], l), f2[n-1] = min (a[n-1], r);
for (int i = 1; i < n; i ++)
f1[i] = min (f1[i-1] + a[i], l*(i+1));
for (int i = n-2; i >= 0; i --)
f2[i] = min (f2[i+1] + a[i], r*(n-i));
int ans = min (f2[0], f1[n-1]);
for (int i = 0; i < n-1; i ++) ans = min (ans, f1[i]+f2[i+1]);
cout << ans << endl;
}
//把前x全变成L,或把后y全变成R
//只能各操作一次
E - Sugoroku 3
题意
\(1\) ~ \(n-1\) 每个上都有一个骰子🎲,数字范围为 \(0\) ~ \(a_i\)
在i上掷出的数字为j,则走到i+j
求在n时的掷骰子次数的期望值
分析
f[i]表示i到n的期望次数(相当于逆推,以n为起点,则f[n]=0)
转移就是枚举每一种可能的步数:\(f[i] = (1+f[i+1]+f[i+2]+...+f[i+a[i]]) / a[i] + 1\) (最开始的1表示投掷到了0)
后缀和优化区间求和
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5, mod = 998244353;
int a[N], f[N], sum[N], n; //后缀和优化
int qmi(int a,int k) {
int ans = 1;
while (k) {
if (k & 1)//末位1取出
ans = ans * a % mod;
k >>= 1;//次末位
a = a * a % mod;
}
return ans;
}
signed main () {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
f[n] = 0, sum[n] = 0;
for (int i = n-1; i >= 1; i --) {
int x = (sum[i+1] - sum[i+a[i]+1] + 1 + mod) % mod, y = a[i] % mod;
f[i] = (x * qmi(y, mod-2) + 1) % mod;
sum[i] = (sum[i+1] + f[i]) % mod;
}
cout << f[1] << endl;
}
//在x上甩出y,就会走到x+y
//f[i]: i走到n的期望次数
//f[i] = (1+f[i+1]+f[i+2]+...+f[i+a[i]]) / a[i] + 1; //要用逆元
//a/b mod p 相当于 a*(qmi(b,p-2) mod p)
F - Tournament
题意
现有\(2^n\)个人,相邻的两个会进行pk,败者淘汰出局
若i赢了j场游戏,则会获得 \(C_{i,j}\) 钱💴
求最大总价值(所有人获得的钱数总和最大)
分析
\(C[i][j]\): 以 \(i\) 为根,取到j的最大值
然后分别搜左子树和右子树即可
位运算+dp
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20, M = (1<<16) + 5;
int C[M][N]; //C[i][j]以i为根,取到j的最大值
signed main () {
int n;
cin >> n;
for (int i = 0; i < 1<<n; i ++)
for (int j = 1; j <= n; j ++)
cin >> C[i][j];
for (int i = 0; i < n; i ++) //枚举根
for (int l = 0; l < 1<<n; l += 1<<i + 1) { //左子树
int r = l | 1 << i; //右子树
for (int j = n; j > i; j --) //如果取的话会深入到哪里
C[l][j] = max (C[l][j] + C[r][i], C[l][i] + C[r][j]); //取左子树or右子树
}
cout << C[0][n] << endl;
}
//记得开ll
G - Erasing Prime Pairs
题意
有n个不同的数,ai会出现bi次
每次可以把这些数里两个和为质数的数拿掉,问最多能操作多少次
分析
不懂
据说是网络流,没学过,学了再补🙅