2020牛客暑期多校训练营(第五场)解题报告

2020牛客暑期多校训练营(第五场)

F. DPS

题目大意

n n n个玩家,每个玩家对敌方的总伤害为 d i d_{i} di,定义其贡献 s = ⌈ 50 × d i m a x j = 1 n d j ⌉ s=⌈50\times\frac{d_{i}}{max_{j=1}^{n}d_{j}}⌉ s=50×maxj=1ndjdi,按照指定格式打印 s s s

解题思路

纯模拟就行了,注意会爆 l o n g l o n g longlong longlong

AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 110;
ll a[maxn];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    ll Max = 0;
    for(int i = 1; i <= n; ++i) {
        cin >> a[i];
        Max = max(Max, a[i]);
    }
    for(int i = 1; i <= n; ++i) {
        ll cnt = (50 * a[i] + Max - 1) / Max;
        cout << '+';
        for(int j = 1; j <= cnt; ++j) cout << '-';
        cout << "+\n";
        cout << '|';
        for(int j = 1; j < cnt; ++j) cout << ' ';
        if(a[i] == Max) cout << '*';
        else if(a[i]) cout << ' ';
        cout << '|';
        cout << a[i] <<'\n';
        cout << '+';
        for(int j = 1; j <= cnt; ++j) cout << '-';
        cout << "+\n";
    }
    return 0;
}

I. Hard Math Problem

题目大意

在一块空地上可以放置三种类型 G G G H H H E E E,其中 H H H必须和至少一个 G G G和至少一个 E E E相邻,定义 f ( n , m ) f(n,m) f(n,m)表示在 n × m n\times m n×m大小的空地上能够放置 H H H的最大数量问你 l i m n → ∞ l i m m → ∞ f ( n , m ) n × m lim_{n\to\infty}lim_{m\to\infty}\frac{f(n,m)}{n\times m} limnlimmn×mf(n,m)是多少

解题思路

. . . ... ...
. . . H E H H E H H E H H E H . . . ...HEHHEHHEHHEH... ...HEHHEHHEHHEH...
. . . G H H G H H G H H G H H . . . ...GHHGHHGHHGHH... ...GHHGHHGHHGHH...
. . . H H E H H E H H E H H E . . . ...HHEHHEHHEHHE... ...HHEHHEHHEHHE...
. . . H G H H G H H G H H G H . . . ...HGHHGHHGHHGH... ...HGHHGHHGHHGH...
. . . E H H E H H E H H E H H . . . ...EHHEHHEHHEHH... ...EHHEHHEHHEHH...
. . . ... ...
所以答案是 2 3 \frac{2}{3} 32

AC代码
#include <bits/stdc++.h>
using namespace std;
int main() {
    printf("0.666667");
    return 0;
}

E. Bogo Sort

题目大意

给你某一个 1 ∽ n 1\backsim n 1n的排列 p p p,假设有一个 1 ∽ n 1\backsim n 1n的排列 a a a,不停地使得 a [ i ] = a [ p [ i ] ] a[i]=a[p[i]] a[i]=a[p[i]],问你有多少种排列经过如上变换最终会变成升序数组

解题思路

置换群求最小置换次数
定义 ∗ * 运算为 a [ i ] = a [ p [ i ] ] a[i]=a[p[i]] a[i]=a[p[i]]
假设 a 1 k 1 = a 1 a_{1}^{k_{1}}=a_{1} a1k1=a1
a 2 k 2 = a 2 a_{2}^{k_{2}}=a_{2} a2k2=a2
a 3 k 3 = a 3 a_{3}^{k_{3}}=a_{3} a3k3=a3
. . . ... ...
那么就是所有置换群中的最大次数( k i k_{i} ki)求 l c m lcm lcm

需要用到 J a v a Java Java大数

AC代码
import java.math.BigInteger;
import java.util.Scanner;

public class Main {
	static int maxn = (int)1e5 + 10;
	static int[] a = new int[maxn];
	static boolean[] vis = new boolean[maxn];
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		BigInteger res = new BigInteger("1");
		BigInteger Mod = new BigInteger("1");
		for(int i = 1; i <= n; ++i) {
			a[i] = sc.nextInt();
			Mod = Mod.multiply(BigInteger.valueOf(10));
		}
		for(int i = 1; i <= n; ++i) {
			if(vis[i]) continue;
			int cnt = 1, cur = i;
			vis[cur] = true;
			while(!vis[a[cur]]) {
				++cnt;
				cur = a[cur];
				vis[cur] = true;
			}
			BigInteger Gcd = res.gcd(BigInteger.valueOf(cnt));
			res = res.multiply(BigInteger.valueOf(cnt).divide(Gcd));
		}
		System.out.println(res.mod(Mod));
		sc.close();
	}
}

D. Drop Voicing

题目大意

给你一个 1 ∽ n 1\backsim n 1n的排列 p p p,有两种操作:

  1. p n − 1 p_{n-1} pn1移动至头部
  2. p 1 p_{1} p1移动到尾部
    其中每次操作可以进行无数次操作一或操作二,问你操作一的最小操作次数
解题思路

操作二相当于将这个数组无限旋转,即将链状数组变成环状数组,操作一相当于将任意一个数提前到任意位置,那么我们固定某一个最长上升子序列相对位置不动,持续移动其他数字即可,那么答案就是 n n n减去环状数组的最大 L I S LIS LIS,时间复杂度 O ( n 2 l o g 2 n ) O(n^{2}log_{2}^{n}) O(n2log2n)

AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
int a[maxn], b[maxn], dp[maxn];
int LIS(int n) {
    memset(dp, 0, sizeof(int) * n);
    int cnt = 1;
    dp[cnt] = b[1];
    for(int i = 2; i <= n; ++i) {
        if(b[i] > dp[cnt]) dp[++cnt] = b[i];
        else dp[lower_bound(dp + 1, dp + cnt + 1, b[i]) - dp] = b[i];
    }
    return cnt;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int res = INT_MAX;
    for(int i = 0; i < n; ++i) {
        for(int j = 1; j <= n; ++j) {
            int index = (j + i) % n;
            if(!index) index = n;
            b[j] = a[index];
        }
        res = min(res, n - LIS(n));
    }
    cout << res << '\n';
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值