Skip to content

Commit

Permalink
3.24
Browse files Browse the repository at this point in the history
  • Loading branch information
dtcxzyw committed Mar 24, 2019
1 parent bc36dcb commit c327271
Show file tree
Hide file tree
Showing 27 changed files with 806 additions and 26 deletions.
1 change: 0 additions & 1 deletion Review/Main.tex
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ \chapter{前言}
\include{CG/CG}
\include{Optmize/Optmize}
\include{Theory/Theory}
\include{STL/STL}
\include{Other/Other}
\appendix
\include{Recommendation}
Expand Down
6 changes: 3 additions & 3 deletions Review/NumberTheory/Dirichlet.tex
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ \subsection{常见技巧}

$\omega(d)$$d$的质因子个数。
\begin{displaymath}
\tau{n^2}=\sum_{d|n}{2^{\omega(d)}}
\tau(n^2)=\sum_{d|n}{2^{\omega(d)}}
\end{displaymath}

证明:考虑$n^2$有而$n$没有的因子,这些因子必定满足其质因子分解中某个质因子指数
Expand All @@ -171,9 +171,9 @@ \subsection{常见技巧}
\mu^2(i)=\sum_{j^2|i}{\mu(j)}
\end{displaymath}

证明:左式的意义是$i$是否含有平方因子(1不算)。若$i$不含平方因子,右式的值
证明:左式的意义是$i$是否含有非平凡平方因子。若$i$不含平方因子,右式的值
$\mu(1)=1$。若$i$含有平方因子,记$i=a^2b$$b$不含平方因子,那么右式变形为
$\sum_{j|a}{\mu(j)}$,因为$a\neq 1$,所以该式的值为0。
$\displaystyle\sum_{j|a}{\mu(j)}$,因为$a\neq 1$,所以该式的值为0。

这些方法参考了Candy?的博客\footnote{
SPOJ DIVCNT2 [我也不知道是什么分类了反正是数论]\\
Expand Down
13 changes: 11 additions & 2 deletions Review/Other/Owys.tex
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,17 @@ \subsection{读入优化}

结果很明显,显式fread/fwrite速度最快。

若需要输入浮点数,在读入连续可显示字符序列后调用strtod。若需要输入输出浮点数,可以
使用支持自定义buffer的std::strstream,不过要注意这个类在C++98中已被弃用。
若需要输入浮点数,直接调用strtod,然后用其参数str\_end重定位。若需要输入输出浮点数,
可以使用支持自定义buffer的std::strstream,不过要注意这个类在C++98中已被弃用。

Update:经过单步调试追踪到strtod在glibc中实现。其具体实现在
\_\_\_\_STRTOF\\\_INTERNAL(/stdlib/strtod\_l.c)中,其实现依赖GMP,性能。。。。
不过scanf的调用链为\_\_scanf(/stdio-common/scanf.c)$\rightarrow$
\_\_vfscanf\_internal(/stdio-common/vfscanf-internal.c)$\rightarrow$
\_\_strtod\_internal(/stdlib/strtod\_l.c),所以。。。。

glibc源代码参见\url{https://sourceware.org/git/?p=glibc.git;a=tree}。
\CJKsout{这才是正宗的意大利面。}
\subsection{快速乘法取模}
当模数的平方超过long long的表示范围时,可以使用类似快速幂的方式计算快速乘法。

Expand Down
2 changes: 2 additions & 0 deletions Review/Other/TricksAndIdeas.tex
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ \subsection{注意事项/常见转化/思想}
\item 树上连通块个数=点数-边数
\item 网格图四连通块个数=格子数-1*2矩形数-2*1矩形数+2*2矩形数+环数
\end{itemize}
\item 注意最小权最少连通块最多只有n-1条边(MST),在合并时可以使用Kruskal保留
有用边。
\end{itemize}
\subsection{比赛注意事项}
\subsubsection{Linux/GCC工具}
Expand Down
4 changes: 3 additions & 1 deletion Review/Polynomial/Advanced.tex
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
\section{多项式高级算法}
{\bfseries 警告:慎卡常导致编码/调试困难。}

Update:多项式算法模块化封装已完成,参见~\ref{Module}节与~\ref{Optmize}节的内容。

\subsection{牛顿迭代法}
已知函数$G(z)$,求函数$F(z) \bmod{z^n}$满足$G(F(z))\equiv 0 \pmod{z^n}$

Expand All @@ -27,7 +29,7 @@ \subsubsection{注意事项}
\begin{itemize}
\item 使用FFT加速卷积后及时取模,即把不需要的位置0。当然也可以直接将规模对齐到
2的幂次,最后一次再取模。
\item 卷积时使用$>2$倍模次数的2的幂作为卷积规模,因为除法操作至少需要这么多项
\item 卷积时使用$>2$倍模次数的2的幂作为卷积规模,因为乘法操作至少需要这么多项
才足够确定多项式系数。
\item 若要求$\bmod{z^n}$意义下的结果,求导/积分这类导致多项式次数变化的操作,
显然仅把次数设为$n$会导致信息丢失,而且讨论每种操作的最高次数也很麻烦。不妨全部求
Expand Down
2 changes: 1 addition & 1 deletion Review/Polynomial/Module.tex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
\section{FFT封装}
\section{多项式算法封装}\label{Module}
牛顿迭代法/分治FFT时使用。

使用vector存储多项式。
Expand Down
2 changes: 1 addition & 1 deletion Review/Polynomial/Optmize.tex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
\section{计算形式幂级数的牛顿迭代法的常数优化}
\section{计算形式幂级数的牛顿迭代法的常数优化}\label{Optmize}
该内容基于negiizhao的博客\footnote{
\CJKsout{noip退役选手的一些扯淡}关于优化形式幂级数计算的牛顿法的常数\\
\url{http://negiizhao.blog.uoj.ac/blog/4671}
Expand Down
3 changes: 0 additions & 3 deletions Review/STL/STL.tex

This file was deleted.

10 changes: 0 additions & 10 deletions Review/STL/bitset.tex

This file was deleted.

3 changes: 3 additions & 0 deletions Review/String/Convolution.tex
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ \subsection{广义模式匹配}
注意有可能出现一些匹配位置导致模式方阵在母方阵上面展开后错位的情况,因为实际上这个
匹配位置会导致模式方阵放上去后越界。为了避免这种情况,需要根据模式方阵的大小确定这个
匹配位置是否合法。

有些题目还要求某些匹配位置的模式覆盖面积,同样可以将其转换为串,用模式起始位置与模式
覆盖点卷积,最后可以得到每个点的覆盖次数。
77 changes: 77 additions & 0 deletions Source/Competition/FCS2019/Day1/highwayC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
const int size = 100005;
struct Edge {
int u, v, w;
} E[size];
bool cmp(int a, int b) {
return E[a].w < E[b].w;
}
typedef std::vector<int> ES;
int n, fa[105];
int find(int x) {
return fa[x] ? fa[x] = find(fa[x]) : x;
}
ES merge(const ES& A, const ES& B) {
ES X(A.size() + B.size());
std::merge(A.begin(), A.end(), B.begin(), B.end(),
X.begin(), cmp);
ES Y;
memset(fa + 1, 0, sizeof(int) * n);
for(int i = 0, ecnt = n - 1; i < X.size(); ++i) {
Edge& e = E[X[i]];
int u = find(e.u), v = find(e.v);
if(u != v) {
Y.push_back(X[i]);
fa[u] = v;
if(--ecnt == 0)
break;
}
}
return Y;
}
ES G[size << 2];
#define ls l, m, id << 1
#define rs m + 1, r, id << 1 | 1
void build(int l, int r, int id) {
if(l == r)
G[id].push_back(l);
else {
int m = (l + r) >> 1;
build(ls);
build(rs);
G[id] = merge(G[id << 1], G[id << 1 | 1]);
}
}
ES query(int l, int r, int id, int nl, int nr) {
if(nl <= l && r <= nr)
return G[id];
else {
int m = (l + r) >> 1;
if(nl <= m && m < nr)
return merge(query(ls, nl, nr),
query(rs, nl, nr));
if(nl <= m)
return query(ls, nl, nr);
return query(rs, nl, nr);
}
}
int main() {
int m, q;
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; ++i)
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
build(1, m, 1);
for(int i = 1; i <= q; ++i) {
int l, r;
scanf("%d%d", &l, &r);
ES res = query(1, m, 1, l, r);
int ans = 0;
for(int j = 0; j < res.size(); ++j)
ans += E[res[j]].w;
printf("%d\n", ans);
}
return 0;
}
142 changes: 142 additions & 0 deletions Source/Competition/FCS2019/Day1/sailingC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include <algorithm>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
const int size = 1 << 20;
typedef double FT;
typedef std::complex<FT> Complex;
Complex root[size], invR[size];
int tot;
void init(int n) {
tot = n;
FT base = 2.0 * acos(-1.0) / n;
for(int i = 0; i < n; ++i) {
root[i] =
Complex(cos(base * i), sin(base * i));
invR[i] = std::conj(root[i]);
}
}
void FFT(int n, Complex* A, const Complex* w) {
for(int i = 0, j = 0; i < n; ++i) {
if(i < j)
std::swap(A[i], A[j]);
for(int l = n >> 1; (j ^= l) < l; l >>= 1)
;
}
for(int i = 2; i <= n; i <<= 1) {
int m = i >> 1, fac = tot / i;
for(int j = 0; j < n; j += i)
for(int k = 0; k < m; ++k) {
Complex &x = A[j + k],
&y = A[j + m + k];
Complex t = y * w[k * fac];
y = x - t;
x += t;
}
}
}
char buf[705 * 705];
int mcnt[705][705];
bool match[705][705], color[705][705];
Complex S[size], T[size];
int n, m, w, h;
void DFS(int x, int y) {
match[x][y] = false;
S[x * m + y] = 1.0;
if(x + 1 + h - 1 <= n && match[x + 1][y])
DFS(x + 1, y);
if(x > 1 && match[x - 1][y])
DFS(x - 1, y);
if(y + 1 + w - 1 <= m && match[x][y + 1])
DFS(x, y + 1);
if(y > 1 && match[x][y - 1])
DFS(x, y - 1);
}
int main() {
scanf("%d%d", &n, &m);
int ml = m + 1, mr = 0, mt = n + 1, mb = 0;
for(int i = 1; i <= n; ++i) {
scanf("%s", buf + i * m + 1);
for(int j = 1; j <= m; ++j)
if(buf[i * m + j] == 'o') {
ml = std::min(ml, j);
mr = std::max(mr, j);
mt = std::min(mt, i);
mb = std::max(mb, i);
}
}
int begS = 1 * m + 1, endS = n * m + m;
int lenS = endS - begS + 1;
int begT = mt * m + ml, endT = mb * m + mr;
int lenT = endT - begT + 1;
int end = lenS + lenT + 1;
w = mr - ml + 1, h = mb - mt + 1;
int p = 1;
while(p < end)
p <<= 1;
init(p);
//#
{
memset(S, 0, sizeof(Complex) * p);
memset(T, 0, sizeof(Complex) * p);
for(int i = begS; i <= endS; ++i)
S[i - begS + 1] = (buf[i] == '#');
for(int i = begT; i <= endT; ++i)
T[i - begT + 1] = (buf[i] != 'o');
std::reverse(T + 1, T + lenT + 1);
FFT(p, S, root);
FFT(p, T, root);
for(int i = 0; i < p; ++i)
S[i] *= T[i];
FFT(p, S, invR);
for(int i = 1; i + h - 1 <= n; ++i)
for(int j = 1; j + w - 1 <= m; ++j)
mcnt[i][j] += round(
S[lenT + (i * m + j - begS + 1)]
.real() /
p);
}
// o
{
memset(S, 0, sizeof(Complex) * p);
memset(T, 0, sizeof(Complex) * p);
for(int i = begS; i <= endS; ++i)
S[i - begS + 1] = (buf[i] != '#');
for(int i = begT; i <= endT; ++i)
T[i - begT + 1] = 1.0;
std::reverse(T + 1, T + lenT + 1);
FFT(p, S, root);
FFT(p, T, root);
for(int i = 0; i < p; ++i)
S[i] *= T[i];
FFT(p, S, invR);
for(int i = 1; i + h - 1 <= n; ++i)
for(int j = 1; j + w - 1 <= m; ++j)
mcnt[i][j] += round(
S[lenT + (i * m + j - begS + 1)]
.real() /
p);
}
for(int i = 1; i + h - 1 <= n; ++i)
for(int j = 1; j + w - 1 <= m; ++j)
match[i][j] = (mcnt[i][j] >= lenT);
memset(S, 0, sizeof(Complex) * p);
memset(T, 0, sizeof(Complex) * p);
DFS(mt, ml);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(buf[i * m + j] == 'o')
T[i * m + j - begT] = 1.0;
FFT(p, S, root);
FFT(p, T, root);
for(int i = 0; i < p; ++i)
S[i] *= T[i];
FFT(p, S, invR);
int res = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
res += (S[i * m + j].real() / p >= 0.5);
printf("%d\n", res);
return 0;
}
Loading

0 comments on commit c327271

Please sign in to comment.