Edu Round#83(div2)
昨天晚上又没有参加 (CF) ,已经好久没有打了。决定今天老老实实补提
(A,B,C) 好像比较水。
A 、Two Regular Polygons
for _ in range(int(input())):
n,m = map(int,input().split())
if n % m == 0:
print("YES")
else:
print("NO")
B、Bogosort
for _ in range(int(input())):
n = int(input())
L = list(map(int,input().split()))
L.sort()
print(*L[::-1])
C、 Adding Powers
for _ in range(int(input())):
n,k = map(int,input().split())
L = list(map(int,input().split()))
ok = True
bit = [0] * 100
for x in L:
while x > 0:
base = 1
p = 0
while base * k <= x:
base *= k
p += 1
bit[p] += 1
x -= base
for i in range(100):
if bit[i] > 1:
ok = False
break
if ok:
print("YES")
else:
print("NO")
D、 Count the Arrays
题意:
给定 (n,m) 问,满足如下条件的数组的个数,对 (998244353) 取模
- 数组长度是 (n)
- 每个元素在 ([1,m]) 内
- 每个组数中有且仅有一对元素的值相等
- 存在一个下标 (p) ,使得区间 ([1,p]) 严格递增,([p,n]) 严格递减
思路:
- 首先从 (m) 个数中选出 (n-1) 个不同的数,选择方法有 (C_{ m}^{ n-1})
- 选一个数复制一份,不能选最大的,有 (n-2) 个选择
- 而对于剩下的 (n-3) 个数,(除去最大的和一对),他们有两种选择,可以在最大数的左边或则右边,这里有 (2^{n-3}) 种选法
[Ans = C_{ m}^{ n-1} cdot (n-2) cdot 2^{n-3}
]
代码:
这个线性推阶乘和逆元的式子。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll qpow(ll a, ll n) {
ll ans = 1;
while (n) {
if (n & 1ll) {
ans = ans * a % mod;
}
a = 1ll * a * a % mod;
n >>= 1ll;
}
return ans;
}
ll Get_Inv(ll n) {
return qpow(n, mod - 2);
}
const ll maxn = 2e5 + 10;
ll fac[maxn], inv[maxn];
void init() {
fac[0] = 1;
for (ll i = 1; i < maxn; i++) {
fac[i] = 1ll*fac[i - 1] * i % mod;
}
inv[maxn - 1] = Get_Inv(fac[maxn - 1]);
for (ll i = maxn - 2; i >= 0; i--) {
inv[i] = 1ll*inv[i + 1] * (i + 1) % mod;
}
}
ll C(ll m, ll n) { // $C^m_n$
if (n < m || n < 0) return 0;
return 1ll*fac[n] * inv[n - m] % mod * inv[m] % mod;
}
ll n, m;
int main() {
cin >> n >> m;
init();
if (n == 2) {
cout << 0 << endl;
return 0;
}
ll ans = C(n - 1, m) * qpow(2, n - 3) % mod * (n - 2ll) % mod;
cout << ans << endl;
}
E、 Array Shrinking
题意:
有一个序列,你可以选择一对相邻的数字 (a_i=a_{i+1}),然后将这两个数字换为(a_i+1)。
问最后最少能留下多少个数字。
在 (CF) 上看了别人的代码,看了一个感觉特别好理解。
这道题应该是区间Dp
#include<bits/stdc++.h>
using namespace std;
const int maxn = 550;
int p[maxn][maxn];// p[i][j] 表示区间 [i,j] 能否合成一个数
int dp[maxn];
int stk[maxn];
int top;
int A[maxn];
int main(){
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",A+i);
}
for(int l = 1;l <= n;l++){
top = 0;
for(int r = l;r <= n;r++){
stk[++top] = A[r];
while(top > 1){
if(stk[top] == stk[top-1]){
top--;
stk[top]++;
}
else{
break;
}
}
if(top == 1){
p[l][r] = 1;
}
}
}
for(int i = 1;i <= n;i++){
dp[i] = i;
for(int j = 1;j <= i;j++){
if(p[j][i]){
dp[i] = min(dp[i],dp[j-1] + 1);
}
}
}
printf("%d
",dp[n]);
}