A A A
50 50 50 以内的质数个数为15.
暴力搜索, 然后判断即可.
int n, p[N], a[N], tot;
ll ans = 1e18;
bool v[N], cho[N];
void dfs(int x, ll y) {
if (y >= ans)
return;
if (x == tot + 1) {
FOR(i, n) if (__gcd((ll)a[i], y) == 1) return;
ans = y;
return;
}
dfs(x + 1, y * p[x]);
dfs(x + 1, y);
}
void solve() {
n = 50;
rep(i, 2, n) if (!v[i]) {
for (int j = i * i; j <= n; j += i)
v[j] = 1;
}
qr(n);
FOR(i, n) {
qr(a[i]);
int x = a[i];
for (int j = 2; j <= x; j++)
if (x % j == 0) {
while (x % j == 0)
x /= j;
if (!cho[j])
cho[j] = 1, p[++tot] = j;
}
}
dfs(1, 1);
pr2(ans);
}
B B B
每个环都可选可不选…
int n, a[N], tot, deg[N], vis[N];
void solve() {
qr(n);
FOR(i, n) qr(a[i]), deg[a[i]]++;
static int q[N], l, r;
l = 1;
r = 0;
FOR(i, n) if (!deg[i]) q[++r] = i;
while (l <= r) {
int x = q[l++], y = a[x];
vis[x] = 1;
if (!--deg[y])
q[++r] = y;
}
ll ans = 1;
FOR(i, n) if (!vis[i]) {
int x = a[i], y;
ans = ans * 2 % mod;
while (!vis[x])
vis[x] = 1, x = a[x];
}
pr2(ans - 1);
}
C C C
显然我们从小到大处理每一个值.
如果对于 i < j , a i = a j , ∀ i < k < j , a k > a i i < j, a_i = a_j, \forall i < k < j, a_k > a_i i<j,ai=aj,∀i<k<j,ak>ai, 我们连一条边 ( i , j ) (i,j) (i,j).
这样一个排列的答案 = 生成图的连通块数.
我们枚举每一个对 ( i , j ) (i, j) (i,j), 考虑存在边 ( i , j ) (i,j) (i,j) 的方案数.
∑ x = 1 m ( m − x ) j − i − 1 m n − ( j − i ) − 1 \sum_{x=1}^m (m-x)^{j-i-1} m ^{n -(j-i)-1} ∑x=1m(m−x)j−i−1mn−(j−i)−1.
前面这一部分我们可以 O ( n m ) O(nm) O(nm) 预处理.
然后我们可以暴力枚举 ( i , j ) (i,j) (i,j), 当然也可以直接枚举 j − i j-i j−i.
int n, m;
ll s[N], p[N];
void solve() {
qr(n, m);
p[0] = 1;
FOR(i, n) p[i] = p[i - 1] * m % mod;
rep(i, 0, m - 1) {
ll t = 1;
FOR(j, n) ad(s[j], t), t = t * i % mod;
}
ll ans = p[n] * n % mod;
FOR(i, n) {
FOR(j, i - 1) { dl(ans, s[i - j] * p[n - (i - j) - 1] % mod); }
}
pr2(ans);
}
D D D
先对 a a a 排个序.
设 b i b_i bi 为 第 i i i 个点的目标位置.
显然有 b 1 ≤ b 2 ≤ . . . ≤ b n b_1\le b_2\le ...\le b_n b1≤b2≤...≤bn.
我们对 a i , b i a_i, b_i ai,bi 维护每个位置的出现次数, 然后可以发现最后出现次数为奇数的集合正好为 t t t.(我们设 v i v_i vi 表示第 i i i 个位置的两边是否相同, 那么加入一条路径相当于 v a i xor = 1 , v b i xor = 1 v_{a_i} \text {xor}= 1,v_{b_i} \text{xor} = 1 vaixor=1,vbixor=1)
但是 b b b 是未知的, 我们可以发现 可重集 ∪ { a i } ∪ { t i } \cup \{a_i\} \cup \{t_i\} ∪{ai}∪{ti} 中出现出现奇数次的 一定在 b b b 中出现过.
这样我们就可以 dp \text {dp} dp 啦: 定义 f [ i ] [ j ] f[i][j] f[i][j] 表示 前 i i i 个 a a a, 配对前 j j j 个 b b b.
每次转移既可以和 b b b 配对, 也可以和下一个 a a a 配对.
复杂度 O ( n k ) O(nk ) O(nk)
int n, m, a[N], t, c[N * 2];
ll f[N][N];
map<int, int> s;
void solve() {
qr(n, m);
FOR(i, n) qr(a[i]), s[a[i]] ^= 1;
int v;
FOR(i, m) qr(v), s[v] ^= 1;
sort(a + 1, a + n + 1);
for (auto i : s)
if (i.se)
c[++t] = i.fi;
if (t > n || (n - t) & 1) {
puts("-1");
return;
}
memset(f, 63, sizeof f);
f[0][0] = 0;
rep(i, 0, n - 1) rep(j, 0, min(t, i)) {
ll& v = f[i][j];
if (v >= INF)
continue;
cmin(f[i + 2][j], v + a[i + 2] - a[i + 1]);
cmin(f[i + 1][j + 1], v + abs(a[i + 1] - c[j + 1]));
}
pr2(f[n][t]);
}
E E E
显然有 5 类不同的东西:
左/右边的列, 上/下的行, 中间的行列.
我们把他们依次给他们标号, 然后给所有物品排列.
然后根据期望的线性性, 我们只需要考虑 1 ∼ 4 1\sim 4 1∼4 每种在第一个 5 5 5 前面个数的期望即可.
但是这样不符合题目中抛弃一半的意思, 所以我们给 1 ∼ 4 1\sim 4 1∼4 每种内部在标号, 标号小的可以把标号大的删去.
设 c n t i cnt_i cnti 表示每一类的数量.
那么对于一类中标号为
j
j
j 的被选到当且仅当 它是
[
1
,
j
]
[1,j]
[1,j] 和所以第 5 类 中第一个被选到的, 故概率为
1
j
+
c
n
t
5
\dfrac 1 {j + cnt_5}
j+cnt51
A
n
s
=
∑
i
=
1
4
∑
j
=
1
c
n
t
i
1
j
+
c
n
t
5
Ans = \sum_{i=1}^4 \sum_{j = 1}^{cnt_i} \dfrac 1 {j + cnt_5}
Ans=i=1∑4j=1∑cntij+cnt51
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
typedef long long ll;
#define rep(i, a, b) for (int i = a; i <= b; i++)
int n, m, u, v, w, z, s, inv[200010], S;
ll calc(int x) {
ll s = 0;
while (x)
s += inv[x-- + S];
return s;
}
int main() {
cin >> n >> m >> u >> v >> w >> z;
if (u > w)
swap(u, w);
if (v > z)
swap(v, z);
inv[0] = inv[1] = 1;
rep(i, 2, n + m) inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod;
S = w - u + z - v;
cout << (calc(u - 1) + calc(n - w) + calc(v - 1) + calc(m - z) + 1) % mod << "\n";
}
F F F
显然这种题还是不要做了
可以发现 Q ≥ P Q \ge P Q≥P, k k k 越小 Q Q Q 越小.
对于一个划分, Q Q Q 显然就是每段的第一个元素排序后拼接起来的结果.
然后,我们来讨论一下 P 1 P_1 P1:
-
P 1 ≤ k P_1 \le k P1≤k, 显然每一段的开头分别为 [ 1 , k ] [1,k] [1,k], 否则的话, 第一个位置可以更大…
-
否则, 我们要做到字典序最小必须保证 P , Q P,Q P,Q 的相同前缀尽可能的长.于此同时, 希望后面部分的划分尽可能少.
为了满足第二部分, 我们前面应该求一个最长下降子序列.
设 f i f_i fi 表示选定 P 1 , P i P_1, P_i P1,Pi 后最长下降子序列的长度.
那么如果 i i i 后的段开头一定 < P i < P_i <Pi. (否则 P , Q P,Q P,Q 的相同前缀长度缩小.)
如果后面 < P i <P_i <Pi 的个数 ≥ m − f i \ge m - f_i ≥m−fi, 为了优先满足第一部分, 我们应该选择 < P i <P_i <Pi 的下表更大的 m − f i m-f_i m−fi 个作为剩下的段开头.
综上, 我们按 P i P_i Pi 从小到大枚举, 然后用树状数组 / 平衡树 维护一下下标集合, 即可求出最大公共前缀.
剩下的部分排序即可解决.
TP void cmax(o& x, o y) {
if (x < y)
x = y;
}
int n, m, a[N], b[N], f[N], sta[N], top, p[N];
template <typename T> struct BIT {
T* c;
int n, lg; // require you to define 0 as the initial value !!
BIT(int _n)
: n(_n) {
c = new T[n];
lg = __lg(n);
c--;
FOR(i, n) c[i] = T(0);
}
void add(int x, T y) {
for (; x <= n; x += x & -x)
c[x] = c[x] + y;
}
int Kth(int k) {
#define bin(x) (1 << (x))
int x = 0;
REP(i, 0, lg) if (bin(i) + x <= n && c[bin(i) + x] < k) k -= c[x += bin(i)];
return x + 1;
}
};
bool vis[N];
void solve() {
qr(n, m);
sta[0] = 0;
FOR(i, n) {
qr(a[i]);
b[a[i]] = i;
int x = n - a[i] + 1;
if (sta[top] < x)
sta[++top] = x, f[i] = top;
else if (a[i] <= a[1])
f[i] = lower_bound(sta + 1, sta + top + 1, x) - sta, sta[f[i]] = x;
else
f[i] = -n;
}
if (top >= m) {
FOR(i, n) pr1(a[i]);
puts("");
return;
}
BIT<int> tr(n);
int pos = 0, mx = 0; //最大的同步右端点
FOR(i, n) {
int x = b[i], y = tr.Kth(i - (m - f[x]));
tr.add(x, 1);
if (y == n + 1)
continue;
if (x < y) {
if (--y > pos)
pos = y, mx = f[x];
else if (y == pos)
cmax(mx, f[x]);
}
}
iota(p, p + n - pos + 1, pos);
sort(p + 1, p + n - pos + 1, [](int x, int y) { return a[x] < a[y]; });
int res = m - mx;
debug(pos);
debug(res);
vis[n + 1] = 1;
FOR(i, pos) pr1(a[i]);
FOR(i, res) vis[p[i]] = 1;
REP(i, 1, res) {
int x = p[i];
do
pr1(a[x++]);
while (!vis[x]);
}
}