C.Median Sum
D.Min Max Repetition
最短相同子串长度 x = ⌈ max ( A , B ) min ( A , B ) + 1 ⌉ x=\lceil\dfrac{\max(A,B)}{\min(A,B)+1}\rceil x=⌈min(A,B)+1max(A,B)⌉
字典序最小的串必然前半部分是一段 A × x , B , A × x , . . . A\times x,B,A\times x,... A×x,B,A×x,...
存在位置 p o s pos pos使得前半部分维持到 p o s pos pos时,剩余的 A ′ , B ′ A',B' A′,B′满足 B ′ > A x B'>Ax B′>Ax
从 ( p o s + 1 ) − ( A + B ) (pos+1)-(A+B) (pos+1)−(A+B)的后半部分就是一段 B . . B , A , B × x , A , B × x B..B,A,B\times x,A,B\times x B..B,A,B×x,A,B×x
二分寻找 p o s pos pos即可。
E.Encoding Subsets
区间DP:
设 f [ S ] , g [ S ] f[S],g[S] f[S],g[S]分别表示01串 S S S子集的方案数和不可分割(长度为1或左右均为括号)的方案数。
边界 g [ ∣ S ∣ ] = S − ′ 0 ′ ( ∣ S ∣ = 1 ) , f [ 空 串 ] = 1 g[|S|]=S-'0' \ \ (|S|=1),f[空串]=1 g[∣S∣]=S−′0′ (∣S∣=1),f[空串]=1,转移:
f
[
S
]
=
∑
T
是
S
的
前
缀
且
T
不
为
空
串
g
[
T
]
×
f
[
S
−
T
]
f[S]=\sum\limits_{T是S的前缀且T不为空串}g[T]\times f[S-T]
f[S]=T是S的前缀且T不为空串∑g[T]×f[S−T]
g
[
S
]
=
∑
T
是
S
的
循
环
节
且
T
≠
S
f
[
T
]
g[S]=\sum\limits_{T是S的循环节且T \neq S}f[T]
g[S]=T是S的循环节且T̸=S∑f[T]
g
g
g转移的时候把强制有循环节按位与即可。
答案是
f
[
原
串
]
f[原串]
f[原串]
玄学记搜就过了
code from xyz32768
#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int PYZ = 998244353;
map<string, int> f, g;
int F(string); int G(string);
int G(string s) {
if (g[s]) return g[s]; int i, n = s.size(); if (n == 1) return g[s] = s[0] - '0' + 1;
int j, k, res = 0; For (i, 1, n - 1) if (n % i == 0) {
string t = ""; For (j, 1, i) {
int r = 1; Step (k, j - 1, n - 1, i) r &= s[k] - '0';
t += (char) (r + '0');
}
res = (res + F(t)) % PYZ;
}
return g[s] = res;
}
int F(string s) {
if (f[s]) return f[s]; int i, n = s.size(); if (!n) return f[s] = 1;
int res = 0; For (i, 1, n)
res = (res + 1ll * G(s.substr(0, i)) * F(s.substr(i, n)) % PYZ) % PYZ;
return f[s] = res;
}
int main() {
string s; cin >> s; cout << F(s) << endl;
return 0;
}
*F.Arcs on a Circle
Tourist的神题,做是不可能做出来的,题解wxh010910:
取 L L L最大的弧的左端点为原点。其它弧的左端点都可以用一个实数表示。
发现位置整数部分是 [ 0 , C ) [0,C) [0,C)的一个随机值,小数部分是 [ 0 , 1 ) [0,1) [0,1)均匀随机的一个实数。我们不关心小数部分的具体值,只关心 n n n条弧的小数部分相对大小。
于是
(
n
−
1
)
!
(n-1)!
(n−1)!枚举小数部分相对大小的排列(等概率出现) ,在
N
×
C
N\times C
N×C个位置上DP:
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示已经放上的圆弧状态为
j
j
j,覆盖最远点为
i
i
i的方案数。
code from Factorio
#include <bits/stdc++.h>
using namespace std;
double z, f[320][33], t;
int n, c, a[9];
int main() {
cin >> n >> c;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
do {
memset(f, 0, sizeof f);
f[n * a[n - 1]][0] = 1;
for (int i = 0; i < n * c; i++) {
for (int j = i; j <= n * c; j++) {
for (int k = 0; k < (1 << (n - 1)); k++) {
if (i % n && (k >> (i % n - 1) & 1) == 0) {
f[min(max(j, i + n * a[i % n - 1]), n * c)][k | (1 << (i % n - 1))] += f[j][k];
}
}
}
}
z += f[n * c][(1 << (n - 1)) - 1];
t++;
} while (next_permutation(a, a + n - 1));
printf("%.15f\n", z / t / pow(c, n - 1));
return 0;
}