friend inline matrix operator * (const matrix &a, const matrix &b)
{
matrix c;
c.Clear(a.gn, b.gm);
for (int i = 0; i < a.gn; ++i)
for (int k = 0; k < a.gm; ++k)
{
int s = a.g[i][k];
for (int j = 0; j < b.gm; ++j)
c.g[i][j] = (1ll * s * b.g[k][j] + c.g[i][j]) % mod;
}
return c;
}
证明 假设有矩阵 D = A B C D = ABC D=ABC,需证明 D = A ( B C ) D = A(BC) D=A(BC),即
D i , j = ⨁ l = 1 n ( A B ) i , l ⊗ C l , j = ⨁ l = 1 n ( ⨁ k = 1 n A i , k ⊗ B k , l ) ⊗ C l , j = ⨁ l = 1 n ⨁ k = 1 n A i , k ⊗ B k , l ⊗ C l , j = ⨁ k = 1 n ⨁ l = 1 n A i , k ⊗ B k , l ⊗ C l , j = ⨁ k = 1 n ⨁ l = 1 n A i , k ⊗ ( B k , l ⊗ C l , j ) = ⨁ k = 1 n A i , k ⊗ ( ⨁ l = 1 n B k , l ⊗ C l , j ) = ⨁ k = 1 n A i , k ⊗ ( B C ) k , j \begin{aligned} D_{i,j} &= \bigoplus\limits_{l=1}^{n} (AB)_{i,l}\otimes C_{l,j} \\ &= \bigoplus\limits_{l=1}^{n} \left(\bigoplus\limits_{k=1}^{n} A_{i,k}\otimes B_{k,l}\right)\otimes C_{l,j} \\&= \bigoplus\limits_{l=1}^{n} \bigoplus\limits_{k=1}^{n} A_{i,k}\otimes B_{k,l}\otimes C_{l,j}\\&= \bigoplus\limits_{k=1}^{n} \bigoplus\limits_{l=1}^{n} A_{i,k}\otimes B_{k,l}\otimes C_{l,j}\\&= \bigoplus\limits_{k=1}^{n} \bigoplus\limits_{l=1}^{n} A_{i,k}\otimes \left(B_{k,l}\otimes C_{l,j}\right)\\&= \bigoplus\limits_{k=1}^{n} A_{i,k}\otimes \left(\bigoplus\limits_{l=1}^{n}B_{k,l}\otimes C_{l,j}\right)\\&= \bigoplus\limits_{k=1}^{n} A_{i,k}\otimes(BC)_{k,j} \end{aligned} Di,j=l=1⨁n(AB)i,l⊗Cl,j=l=1⨁n(k=1⨁nAi,k⊗Bk,l)⊗Cl,j=l=1⨁nk=1⨁nAi,k⊗Bk,l⊗Cl,j=k=1⨁nl=1⨁nAi,k⊗Bk,l⊗Cl,j=k=1⨁nl=1⨁nAi,k⊗(Bk,l⊗Cl,j)=k=1⨁nAi,k⊗(l=1⨁nBk,l⊗Cl,j)=k=1⨁nAi,k⊗(BC)k,j
l = 0, ql = 1, qr = 0;
for (int i = 1; i <= n; ++i)
{
while (l < i && sum[i] - sum[l] > M)
++l;
while (ql <= qr && sum[i] - sum[que[ql]] > M)
val[que[ql++]] = -1;
while (ql <= qr && a[que[qr]] <= a[i])
val[que[--qr]] = -1;
if (ql <= qr)
q.push(point(val[que[qr]] = f[que[qr]] + a[i], que[qr]));
que[++qr] = i;
f[i] = f[l] + a[que[ql]];
while (!q.empty() && val[q.top().t] != q.top().s)
q.pop();
if (!q.empty())
CkMin(f[i], q.top().s);
}
Splay
操作,减少了部分常数。namespace Hull
{
const int N = 1e5 + 5;
int rt;
int fa[N], lc[N], rc[N];
int suf[N], pre[N];
ll valx[N], valy[N];
inline void Init(int x, ll vx, ll vy)
{
valx[x] = vx;
valy[x] = vy;
}
inline bool Slope1(int x, int y, int z)
{
if (!x || !y || !z)
return true;
return (valy[y] - valy[x]) * (valx[z] - valx[y])
<= (valy[z] - valy[y]) * (valx[y] - valx[x]);
}
inline bool Slope2(int x, int y, ll z)
{
if (!x || !y)
return true;
return (valy[y] - valy[x]) <= z * (valx[y] - valx[x]);
}
inline void Rotate(int x)
{
int y = fa[x], z = fa[y];
bool flag = lc[y] == x;
int b = flag ? rc[x] : lc[x];
fa[x] = z, fa[y] = x;
b ? fa[b] = y : 0;
z ? (lc[z] == y ? lc[z] : rc[z]) = x : 0;
flag ? (rc[x] = y, lc[y] = b) : (lc[x] = y, rc[y] = b);
}
inline bool whichSide(int x)
{
return rc[fa[x]] == x;
}
inline void Splay(int x, int tar)
{
while (fa[x] != tar)
{
if (fa[fa[x]] != tar)
Rotate(whichSide(fa[x]) == whichSide(x) ? fa[x] : x);
Rotate(x);
}
!tar ? rt = x : 0;
}
inline int findLeft(int x, int y)
{
int res = x;
while (x)
{
if (Slope1(pre[x], x, y))
res = x, x = rc[x];
else
x = lc[x];
}
return res;
}
inline int findRight(int x, int y)
{
int res = x;
while (x)
{
if (Slope1(y, x, suf[x]))
res = x, x = lc[x];
else
x = rc[x];
}
return res;
}
inline void Clear(int &x)
{
if (!x)
return ;
Clear(lc[x]);
Clear(rc[x]);
fa[x] = pre[x] = suf[x] = 0;
x = 0;
}
inline void Insert(int id)
{
int x = rt, y = 0, dir;
while (x)
{
y = x;
if (valx[id] < valx[x])
x = lc[x], dir = 0;
else
x = rc[x], dir = 1;
}
fa[x = id] = y;
if (y) (dir ? rc[y] : lc[y]) = x;
Splay(x, 0);
if (lc[x])
{
int z = findLeft(lc[x], x);
Splay(z, x);
Clear(rc[z]);
suf[z] = x;
pre[x] = z;
}
if (rc[x])
{
int z = findRight(rc[x], x);
Splay(z, x);
Clear(lc[z]);
pre[z] = x;
suf[x] = z;
}
if (!Slope1(pre[x], x, suf[x]))
{
rt = lc[x];
rc[rt] = rc[x];
fa[rc[x]] = rt;
fa[rt] = 0;
lc[x] = rc[x] = fa[x] = 0;
suf[rt] = rc[rt];
pre[rc[rt]] = rt;
}
}
inline int Query(ll z)
{
int x = rt, res = 0;
while (x)
{
if (Slope2(pre[x], x, z))
res = x, x = rc[x];
else
x = lc[x];
}
return Splay(res, 0), res;
}
}
f i = max / min { B ( j ) A ( i ) + D ( j ) + f j } + C ( i ) f_i = \max /\min \{B(j)A(i) + D(j) + f_j\} + C(i) fi=max/min{B(j)A(i)+D(j)+fj}+C(i)
证明 待补充。
read(n);
v.push_back(Maxn);
for (int i = 1, x; i <= n; ++i)
{
read(x);
v.push_back(x);
}
v.push_back(Maxn);
while (n > 1)
{
int j, k;
for (k = 1; k <= n; ++k)
if (v[k - 1] < v[k + 1])
break ;
for (j = k - 1; j >= 0; --j)
if (v[j] > v[k - 1] + v[k])
break ;
int sum = v[k - 1] + v[k];
v.erase(v.begin() + k - 1);
v.erase(v.begin() + k - 1);
v.insert(v.begin() + j + 1, sum);
ans += sum;
--n;
}
printf("%d\n", ans);
证明 取凸正多面体一个顶点,设其向外有 n ( n ≥ 3 ) n(n\ge 3) n(n≥3) 条棱,再取凸正多面体一个面,设其为正 m ( m ≥ 3 ) m(m\ge 3) m(m≥3) 边形。则
n V = 2 E ⇔ V = 2 E n m R = 2 E ⇔ R = 2 E m nV=2E \Leftrightarrow V = \dfrac{2E}{n}\\ mR=2E \Leftrightarrow R = \dfrac{2E}{m}\\ nV=2E⇔V=n2EmR=2E⇔R=m2E
带入欧拉公式,得
1 m + 1 n = 1 E + 1 2 \dfrac{1}{m}+\dfrac{1}{n}=\dfrac{1}{E}+\dfrac{1}{2} m1+n1=E1+21
注意到 m , n m,n m,n 不能同时大于 3,且其中一个等于 3 时另一个不能超过 5。
符合条件的 m , n m,n m,n 的解只有五组,如下图所示。
正四面体 | 立方体 | 正八面体 | 正十二面体 | 正二十面体 | |
---|---|---|---|---|---|
R R R | 4 | 6 | 8 | 12 | 20 |
V V V | 4 | 8 | 6 | 20 | 12 |
E E E | 6 | 12 | 12 | 30 | 30 |
内切球半径 | 6 12 a \frac{\sqrt 6}{12}a 126a | 1 2 a \frac{1}{2}a 21a | 6 6 a \frac{\sqrt 6}{6}a 66a | 1 2 5 2 + 11 10 5 a \frac{1}{2}\sqrt{\frac{5}{2}+\frac{11}{10}\sqrt 5}a 2125+10115a | 3 3 + 15 12 a \frac{3\sqrt 3 + \sqrt {15}}{12}a 1233+15a |
外接球半径 | 6 4 a \frac{\sqrt 6}{4}a 46a | 3 2 a \frac{\sqrt 3}{2}a 23a | 2 2 a \frac{\sqrt 2}{2}a 22a | 3 4 ( 1 + 5 ) a \frac{\sqrt 3}{4}(1+\sqrt 5)a 43(1+5)a | 10 + 2 5 4 a \frac{\sqrt{10 + 2\sqrt 5}}{4}a 410+25a |
棱切球半径 | 2 4 a \frac{\sqrt 2}{4}a 42a | 2 2 a \frac{\sqrt 2}{2}a 22a | 1 2 a \frac{1}{2}a 21a | 3 + 5 4 a \frac{3 + \sqrt 5}{4}a 43+5a | 1 + 5 4 a \frac{1+\sqrt 5}{4}a 41+5a |
证明 考虑证明 引理1 和 引理3,则 Pick 定理显然成立。
- 引理1 若两个只有一条公共边的多边形满足 Pick 定理,则将两个多边形去掉公共边,合并成的一个多边形也满足 Pick 定理。
证明 设合并的两个多边形为 P , Q P,Q P,Q,它们的公共边上的格点数(不包括端点)为 c c c。
S = S P + S Q = i P + i Q − b P + b Q 2 − 2 = i − c + b − 2 c − 2 2 − 2 = i + b 2 − 1 \begin{aligned}S &= S_P + S_Q \\&=i_P + i_Q - \frac{b_P + b_Q}{2} - 2\\&= i - c + \frac{b - 2c - 2}{2} - 2\\& =i + \frac{b}{2} - 1 \\\end{aligned} S=SP+SQ=iP+iQ−2bP+bQ−2=i−c+2b−2c−2−2=i+2b−1
- 引理2 有两个只有一条公共边的多边形,若将这两个多边形去掉公共边,合并成的一个多边形满足 Pick 定理,且这两个多边形中有一个满足 Pick 定理,则另一个多边形也满足 Pick 定理。
证明 用类似 引理1 的方法即可。
- 引理3 任意一个三角形都满足 Pick 定理。
证明
已知面积为 1 的正方形满足 Pick 定理,由 引理1 得任意大小的矩形都满足 Pick 定理。
将一个矩形拆分为两个全等的直角三角形,证明任意一个直角三角形都满足 Pick 定理。
证明 设两个直角三角形公共边上的格点数(不包括端点)为 c c c,原矩形为 R R R,拆分出的直角三角形为 T T T。
S T = S R 2 = i R 2 + b R 4 − 1 2 = 2 i T + c 2 + 2 b T − 2 c − 2 4 − 1 2 = i T + b T 2 − 1 \begin{aligned}S_T &= \frac{S_R}{2} \\ &= \frac{i_R}{2} + \frac{b_R}{4} - \frac{1}{2} \\&= \frac{2i_T + c}{2} + \frac{2b_T - 2c - 2}{4} - \frac{1}{2} \\&= i_T + \frac{b_T}{2} - 1\\\end{aligned} ST=2SR=2iR+4bR−21=22iT+c+42bT−2c−2−21=iT+2bT−1任意一个三角形显然可以由一个矩形拆去不多于3个的直角三角形得到,由 引理2 可知得证。
#include
typedef long long ll;
typedef long double ld;
const int N = 1e5 + 5;
const ld eps = 1e-8;
int n, top, pos[N];
ld ans;
struct point
{
ld x, y;
point() {}
point(ld X, ld Y):
x(X), y(Y) {}
inline void scan()
{
double _x, _y;
scanf("%lf%lf", &_x, &_y);
x = _x, y = _y;
}
inline bool operator < (const point &a) const
{
return x < a.x || fabsl(x - a.x) <= eps && y < a.y;
}
inline ld dist() const
{
return x * x + y * y;
}
inline point operator - (const point &a) const
{
return point(x - a.x, y - a.y);
}
inline ld operator * (const point &a) const
{
return x * a.y - y * a.x;
}
}p[N], stk[N];
inline bool cmp(const int &x, const int &y)
{
ld del = p[x] * p[y];
if (fabsl(del) <= eps)
return p[x].dist() < p[y].dist();
else
return del > 0;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
p[i].scan();
int id = 1;
for (int i = 2; i <= n; ++i)
if (p[i] < p[id])
id = i;
if (id != 1)
std::swap(p[id], p[1]);
for (int i = n; i >= 1; --i)
pos[i] = i, p[i] = p[i] - p[1];
std::sort(pos + 2, pos + n + 1, cmp);
stk[top = 1] = p[1];
for (int i = 2; i <= n; ++i)
{
int j = pos[i];
while (top > 1 && (p[j] - stk[top - 1]) * (stk[top] - stk[top - 1]) >= -eps) --top;
stk[++top] = p[j];
}
for (int i = 1; i < top; ++i)
ans += sqrtl((stk[i] - stk[i + 1]).dist());
ans += sqrtl((stk[top] - stk[1]).dist());
printf("%.2lf\n", (double)ans);
}