F. DPS

签到。题意为将给定的数据用横向条形图画出来。

I. Hard Math Problem

题意

的网格,每个网格可以放置H、G、E中的一种,要求H旁边必须至少相邻一个G和E,求 当区域趋于无穷大时最大的放置H的数量。

解题思路

最开始想的交叉放置,这样最大利用率趋近,之后的思路是所有的区块都按照3*3放置,利用率是。但这两种方法都WA了。
正确思路:利用率达到最大时,每个G和E都被旁边的四个H利用,那么理想状态下,G:E:H=1:1:4,即结果为

/*
GHHGHHGHHGHH
HHEHHEHHEHHE
HGHHGHHGHHGH
EHHEHHEHHEHH
*/

E. Bogo Sort

题意

有一个的某个排列,给定一个变换序列p[i],每次替换时将数组中每个元素a[i]替换成a[p[i]]。问最多替换多少次可以将原数组排列成的顺序排列。

解题思路

求出每个数环的长度,结果则为环的长度的最小公倍数。结果用python表示,C++用不好会炸。

def gcd(a, b):
    if a % b == 0:
        return b
    else:
        return gcd(b, a % b)

def lcm(a, b):
    return (a//gcd(a, b)*b) % (10**n)

vis = [0]*200005
n = int(input())
num = [int(n) for n in input().split()]
cir = []
ans = 1
for j in num:
    if(vis[j] != 0):
        continue
    cir.clear()
    while(vis[j] == 0):
        vis[j] = 1
        cir.append(j)
        j = num[j-1]
    ans = lcm(ans, len(cir))
print(ans)

D. Drop Voicing

题意

有两种操作:
Drop-2: 把右数第二个数移至最左边。
Invert:环形旋转整个序列一位。
每一步可以进行单个操作任意次,求至少多少次后可以将原数组排列成的顺序排列。

解题思路

网上有个题解思路写得很清楚。

花费1即连续的①相当于可以把倒数第二个往前移任意个位置。那么我们可以花费1经连续的①把倒数第二个往前的若干个数移到最前面,然后花费0经②把该的若干个数又移到最后面,所以可以等价于花费1可以把最后一个数移到前面任意两个数之间。

既然可以旋转任意多次,那么,多次Drop-2等价于将一个元素移至任意位置,多次Invert等价于旋转序列任意位。所以这道题即是求整个环形序列的最大上升子序列长度,结果就是n-ans。

// rotate函数用法
rotate(数组首地址, 旋转后数组首地址, 数组末地址);
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;

int dp[maxn], a[maxn];
int ans, n;

int fun(int n) {
    for(int i=0;i<=n;i++) dp[i]=1;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<i;j++) {
            if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1); 
        }
    }
    return dp[n];
} 

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) {
        ans = max(ans, fun(n));
        rotate(a+1,a+2,a+n+1);
    }
    printf("%d\n", n-ans);
}