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

题意

进行如下操作各一次:

  1. \(a_1,a_2,...,a_x\) 全替换为 L;
  2. \(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次
每次可以把这些数里两个和为质数的数拿掉,问最多能操作多少次

分析

不懂
据说是网络流,没学过,学了再补🙅‍

posted @ 2022-08-07 10:43  Sakana~  阅读(118)  评论(0编辑  收藏  举报