T1、列Lの数が少ないです
直列与える\を(\ {F_iと\} \):\
[F_iと= \ prod_ {J = 1} ^ {J \のLeq K} F_ {I - J} ^ {b_j}、\(I> K)\]
今、前の列の数を所定の\(k個の\(K \ル 200)\) という用語と\(B_i} {\)まず探し、\(N- \)キー。
\(ソル\) :
列の任意の数のメモを取った\(F_iと\(I> K)\)され、前者(K \)\ごとに算出それぞれちょうど第一のパワーの積項を\ (N \)貢献項目。
注\(dp_i \)を表し\(Iは\)指数を描画することは困難である:
\ [dp_i = \ J =私はsum_ { - } ^ K {J \ IのLeq - B_ 1} I { - } J \回dp_j \]
前者が列挙されているので、明らかに行列乗算は、最適化するために使用することができる(K \)\項目、時間複雑度\(O(K ^ 4 \ \ N-log_2)\) 。
各遷移行列は、することが可能であり、同じである(O(K ^ 3 \ \ \ log_2のN)\) 複合体を解決するための時間。
コードは以下の通りであります:
#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int M = 205, mod = 998244353;
int n, m, f[205], y[205], a[205], b[205], res;
struct matrix {
int a[M][M];
matrix(int t = 0) {
memset(a, 0, sizeof(a));
if (t > 0)
for (int i = 1; i <= m; ++i)
a[i][i] = t;
}
inline int* operator [] (int x) {
return a[x];
}
inline matrix operator * (matrix &b) const {
matrix ret;
for (int k = 1; k <= m; ++k)
for (int i = 1; i <= m; ++i)
if (a[i][k])
for (int j = 1; j <= m; ++j)
if (b[k][j]) {
ret[i][j] += 1ll * a[i][k] * b[k][j] % (mod - 1);
if (ret[i][j] >= mod - 1)
ret[i][j] -= mod - 1;
}
return ret;
}
} ;
matrix matrix_qpow(matrix base, int b) {
matrix ret(1);
for (; b; b >>= 1, base = base * base)
if (b & 1)
ret = ret * base;
return ret;
}
int qpow(int base, int b, int ret = 1) {
for (; b; b >>= 1, base = 1ll * base * base % mod)
if (b & 1)
ret = 1ll * ret * base % mod;
return ret;
}
int main() {
//freopen("in", "r", stdin);
freopen("seq.in", "r", stdin);
freopen("seq.out", "w", stdout);
matrix trans;
n = in(), m = in();
for (int i = 1; i <= m; ++i)
y[i] = in();
for (int i = 1; i <= m; ++i)
f[i] = in();
if (n <= m) {
printf("%d\n", f[n]);
return 0;
}
for (int i = 1; i <= m; ++i)
trans[i][i - 1] = 1;
for (int i = 1; i <= m; ++i)
trans[i][m] = y[m - i + 1];
res = 1;
trans = matrix_qpow(trans, n - m);
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= m; ++j)
b[j] = a[j] = 0;
b[i] = 1;
for (int k = 1; k <= m; ++k)
for (int j = 1; j <= m; ++j) {
a[j] += 1ll * b[k] * trans[k][j] % (mod - 1);
if (a[j] >= mod - 1)
a[j] -= mod - 1;
}
res = 1ll * res * qpow(f[i], a[m]) % mod;
}
printf("%d\n", res);
return 0;
}
T2、夢
数直線の所定の\(N- \)の線分(\ \ {L_iを、R_iを\} \)、\ (m個\)点(\ \ {T_I \} \) 、各マッチラインセグメントはで選択し、含まれていません線分一致点は、マッチの最大数を見つけます。
\(70pts \) :
セグメントツリー図構造部グラフの最大マッチングを最適化しようとします。
\(100のPTS \):\
(ソル1 \) :
小から大へのポイント、大小規模から左端線分、
小から大への全ての点を列挙する、スタックに線分の点の左側に左ポイントを置く(右端点小根ヒープ)キーワード、
現在の列挙におけるヒープの右スポットチェックトップが右を指すようにし、そうであれば、ポイントおよびヒープ・セグメントの上面と一致するように変更するかどうかは、条件が満たされているか、ヒープになるまでそうでなければ、プロセスを繰り返します空。
最初の場合は\(私は\)ポイントは、ラインの右側のポイントは、より多くの選択肢を持っているので、右の左端のポイントを選択することができるようにするために、その右のポイントにのみ影響を受けることになります。
\(SOL 2 \) :
フェンウィックツリーにライン小から大への右エンドポイントを押し、点、
各セグメントを列挙し、各セグメントは、左の点を維持することを選択しました。
そして\(SOL1 \)と同じ。
コードは以下の通りであります:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int N = 2e5 + 5;
struct node {
int l, r;
inline bool operator < (const node &b) const {
return this->r > b.r;
}
} a[N];
int n, m, t[N];
inline bool cmp(const node &i, const node &j) {
return i.l < j.l;
}
int main() {
//freopen("in", "r", stdin);
freopen("dream.in", "r", stdin);
freopen("dream.out", "w", stdout);
n = in(), m = in();
for (int i = 1; i <= n; ++i)
a[i] = (node){in(), in()};
for (int i = 1; i <= m; ++i)
t[i] = in();
std::sort(a + 1, a + 1 + n, cmp);
std::sort(t + 1, t + 1 + m);
std::priority_queue <node> q;
int pos = 1, res = 0;
for (int i = 1; i <= m; ++i) {
while (pos <= n && a[pos].l <= t[i]) {
if (a[pos].r >= t[i])
q.push(a[pos]);
++pos;
}
while (!q.empty() && q.top().r < t[i])
q.pop();
if (!q.empty() && q.top().r >= t[i])
++res, q.pop();
}
printf("%d\n", res);
return 0;
}
T3、木
\(\ N-)木、所与の点\(Mの\(m個の\当量 10 ^ 5)\) の点(異なる2点保証)、需要の点と一つを超える点の数を含みませんシンプルなパス。
\(ソル\) :
少なくともパスの数を求めて検討する点のペアのセットを含みます。
2次元平面上の経路の終端ポイントは経路を表すことができ、
ポイントのために\(U、V \) :
二つの祖先がある場合-子孫関係(\(U \)する(Vを\ \)祖先)、使用可能なパスの範囲の両端点である\(V \)サブツリー内に加えて)(U \ \を含む\(Vの\)サブツリーの他のすべての点を。
ノー祖先2場合-子孫関係、使用可能なパスの範囲の両端点は、\(U \)サブツリー、\(V \)サブツリー。
押して\(DFS \)平面上のシーケンス、面積を求めている長方形のフットプリントの質問への走査線、維持するために、セグメントツリー。
メンテナンスセグメントツリー:あなたがすることができます(push_downの\を)\ことはできない、原因参加する走査線の特定のセグメントの削除に、よりスケーラブルかつて、私は使用しません\(push_down \) 。
コードは以下の通りであります:
//#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }
const int N = 1e5 + 5;
struct edge {
int next, to;
} e[N << 1];
int ecnt = 1, head[N];
inline void jb(const int u, const int v) {
e[++ecnt] = (edge){head[u], v}, head[u] = ecnt;
e[++ecnt] = (edge){head[v], u}, head[v] = ecnt;
}
//heavy-light deposition begin
int siz[N], hson[N], fa[N], dep[N], fro[N], dfn[N];
void dfs_h(const int u) {
siz[u] = 1;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == fa[u])
continue;
fa[v] = u, dep[v] = dep[u] + 1;
dfs_h(v);
siz[u] += siz[v];
if (siz[v] > siz[hson[u]])
hson[u] = v;
}
}
void dfs_f(const int u, const int tp) {
dfn[u] = ++dfn[0], fro[u] = tp;
if (hson[u])
dfs_f(hson[u], tp);
for (int i = head[u]; i; i = e[i].next)
if (e[i].to != fa[u] && e[i].to != hson[u])
dfs_f(e[i].to, e[i].to);
}
int lca(int u, int v) {
while (fro[u] != fro[v]) {
if (dep[fro[u]] > dep[fro[v]])
std::swap(u, v);
v = fa[fro[v]];
}
return dep[u] < dep[v] ? u : v;
}
int find_son(int u, int v) {
while (fro[v] != fro[u]) {
v = fro[v];
if (fa[v] == u)
return v;
v = fa[v];
}
return hson[u];
}
//heavy-light deposition end
int n, m;
typedef std::pair<int, int> pii;
std::vector<pii> a[N][2];
struct segment_tree {
int sum[N << 2], cnt[N << 2];
void push_up(int p, int tl, int tr) {
if (cnt[p])
sum[p] = tr - tl + 1;
else if (tl == tr)
sum[p] = 0;
else
sum[p] = sum[p << 1] + sum[p << 1 | 1];
}
void modify(int l, int r, int k, int tl = 1, int tr = n, int p = 1) {
if (l <= tl && tr <= r) {
cnt[p] += k;
push_up(p, tl, tr);
return ;
}
int mid = (tl + tr) >> 1;
if (mid >= l)
modify(l, r, k, tl, mid, p << 1);
if (mid < r)
modify(l, r, k, mid + 1, tr, p << 1 | 1);
push_up(p, tl, tr);
}
} T;
int main() {
//freopen("in", "r", stdin);
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
n = in(), m = in();
for (int i = 1; i < n; ++i)
jb(in(), in());
dfs_h(3), dfs_f(3, 3);
for (int i = 1, u, v, w; i <= m; ++i) {
u = in(), v = in(), w = lca(u, v);
if (dfn[u] > dfn[v])
std::swap(u, v);
if (w == u) {
w = find_son(u, v);
a[1][0].push_back(pii(dfn[v], dfn[v] + siz[v] - 1));
a[dfn[w]][1].push_back(pii(dfn[v], dfn[v] + siz[v] - 1));
a[dfn[v]][0].push_back(pii(dfn[w] + siz[w], n));
a[dfn[v] + siz[v]][1].push_back(pii(dfn[w] + siz[w], n));
} else {
a[dfn[u]][0].push_back(pii(dfn[v], dfn[v] + siz[v] - 1));
a[dfn[u] + siz[u]][1].push_back(pii(dfn[v], dfn[v] + siz[v] - 1));
}
}
long long res = 1ll * n * (n - 1) / 2;
for (int i = 1; i < n; ++i) {
for (unsigned j = 0; j < a[i][0].size(); ++j)
T.modify(a[i][0][j].first, a[i][0][j].second, 1);
for (unsigned j = 0; j < a[i][1].size(); ++j)
T.modify(a[i][1][j].first, a[i][1][j].second, -1);
res -= T.sum[1];
}
printf("%lld\n", res);
return 0;
}