[题解]完全交不了qwq

\[\color{red}{\text{校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{The principal is really a god}} \\ \color{pink}{\text{with a closestool on the left and Yongshen on the right}} \\ \color{pink}{\text{holding a sharp pen to pierce the truth}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Le principal est vraiment un dieu}} \\ \color{lightblue}{\text{avec des toilettes à gauche et Yongshen à droite}} \\ \color{lightblue}{\text{tenant un stylo pointu pour percer la vérité}} \\ \color{lightblue}{\text{Qui peut lui résister ? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Principalis deus est, Yongshen a dextris cum latrina}} \\ \color{cyan}{\text{acuto stylo ad perforandum veritatem: quis resistet ei? }} \\ \hline \end{array} \\ \color{red}{\text{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \]




  \(\mathcal{Back\;To\;The\;Menu}\).

2022-02-21 完全交不了qwq

  这场比赛真的有写题解的必要吗?

排队 / Queue

  就是求最长上升子序列和最长上升子序列中必选的元素,后者用方案数判一下就行了。

/** @author Arextre */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
#define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for (int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for (int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template <class T>
inline T fab(T x) {
    return x < 0 ? -x : x;
}
template <class T>
inline void chkmin(T& x, const T rhs) {
    x = std::min(x, rhs);
}
template <class T>
inline void chkmax(T& x, const T rhs) {
    x = std::max(x, rhs);
}

#ifdef USING_FREAD
inline char qkgetc() {
#define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
#undef BUFFERSIZE
}
#define CHARRECEI qkgetc()
#else
#define CHARRECEI getchar()
#endif

template <class T>
inline T readret(T x) {
    x = 0;
    int f = 0;
    char c;
    while (!isdigit(c = CHARRECEI))
        if (c == '-')
            f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48))
        ;
    return f ? -x : x;
}
template <class T>
inline void readin(T& x) {
    x = 0;
    int f = 0;
    char c;
    while (!isdigit(c = CHARRECEI))
        if (c == '-')
            f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48))
        ;
    if (f)
        x = -x;
}
template <class T, class... Args>
inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template <class T>
inline void writln(T x, char c = '\n') {
    if (x < 0)
        putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do
        __stk[++__bit] = x % 10, x /= 10;
    while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

}  // namespace Elaina
using namespace Elaina;

const int Maxn = 1e5;
const int Mod = 1e9 + 9;
const int inv2 = 500000005;
inline void chkadd(int& x, int y) {
    if ((x += y) >= Mod)
        x -= Mod;
}

int a[Maxn + 5], n;

inline void input() {
    readin(n);
    rep(i, 1, n) readin(a[i]);
}

namespace saya {

int mx[Maxn + 5], cnt[Maxn + 5];

#define lowbit(i) ((i) & -(i))

inline void clear() {
    memset(mx, 0, sizeof mx);
    memset(cnt, 0, sizeof cnt);
}

inline void modify(int i, int f, int way) {
    for (; i <= n; i += lowbit(i)) {
        if (mx[i] < f)
            mx[i] = f, cnt[i] = 0;
        if (mx[i] == f)
            chkadd(cnt[i], way);
    }
}

inline pii query(int i) {
    pii ret(0, 0);
    for (; i; i -= lowbit(i)) {
        if (ret.fi < mx[i])
            ret = { mx[i], 0 };
        if (ret.fi == mx[i])
            chkadd(ret.se, cnt[i]);
    }
    return ret;
}

}  // namespace saya
int f[2][Maxn + 5], g[2][Maxn + 5];
inline void solve() {
    int lis = 0, way = 0;
    rep(_, 0, 1) {
        auto& dp = f[_];
        auto& cnt = g[_];
        saya::clear();
        rep(i, 1, n) {
            dp[i] = 1, cnt[i] = 1;
            auto ret = saya::query(a[i]);
            if (ret.fi >= 1)
                dp[i] = ret.fi + 1, cnt[i] = ret.se;
            saya::modify(a[i], dp[i], cnt[i]);
            if (lis < dp[i])
                lis = dp[i], way = 0;
            if (lis == dp[i])
                chkadd(way, cnt[i]);
        }
        reverse(a + 1, a + n + 1);
        rep(i, 1, n) a[i] = n - a[i] + 1;
    }
    way = 1ll * way * inv2 % Mod;
    writln(lis);
    rep(i, 1, n) if (f[0][i] + f[1][n - i + 1] - 1 == lis) {
        if (1ll * g[0][i] * g[1][n - i + 1] % Mod == way)
            writln(i, ' ');
    }
    Endl;
}

signed main() {
    // freopen("samples//queue3.in", "r", stdin);
    freopen("queue.in", "r", stdin);
    freopen("queue.out", "w", stdout);
    input();
    solve();
    return 0;
}

数论 / Tree

  \(N\) 只有 \(50\),这个想怎么做怎么做,我直接设 \(f(u,x)\) 表示 \(u\) 节点上的数为 \(x\) 且它为根时,整棵树的合法方案数。本来应当换根 DP,但是我太懒了,直接把父亲记录下来,然后用 vector 动态开数组,这样就避免了 MLE,至于 DP 转移,就是一个很朴素的莫反,反一反就行了。

/** @author Arextre */

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
#define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxa = 50000;
const int Maxn = 50;
const int Mod = 1e9 + 7;
inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

int prime[Maxa + 5], mu[Maxa + 5];
bool vis[Maxa + 5];
inline void sieve() {
    vis[1] = true, mu[1] = 1;
    rep (i, 2, Maxa) {
        if (!vis[i]) prime[++*prime] = i, mu[i] = Mod - 1;
        for (int j = 1; j <= *prime && i * prime[j] <= Maxa; ++j) {
            vis[i * prime[j]] = true, mu[i * prime[j]] = Mod - mu[i];
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
        }
    }
}

int n;
int l[Maxn + 5], r[Maxn + 5];
vector<int> g[Maxn + 5];

inline void input() {
    readin(n);
    rep (i, 1, n) readin(l[i]);
    rep (i, 1, n) readin(r[i]);
    int u, v;
    rep (i, 2, n) {
        readin(u, v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
}

vector<int> dp[Maxn + 5][Maxn + 5];
vector<int> sum[Maxn + 5][Maxn + 5];
void dfs(int u, int par) {
    if (!dp[u][par].empty()) return ;
    dp[u][par].resize(Maxa + 5, 0);
    rep (i, l[u], r[u]) dp[u][par][i] = 1;
    for (int v: g[u]) if (v ^ par) {
        dfs(v, u);
        rep (i, l[u], r[u])
            dp[u][par][i] = 1ll * dp[u][par][i] * sum[v][u][i] % Mod;
    }
    static int f[Maxa + 5];
    memset(f, 0, sizeof f);
    for (int d = 1; d <= Maxa; ++d) {
        for (int j = d; j <= Maxa; j += d) chkadd(f[d], dp[u][par][j]);
        f[d] = 1ll * f[d] * mu[d] % Mod;
    }
    sum[u][par].resize(Maxa + 5, 0);
    for (int i = 1; i <= Maxa; ++i) {
        for (int j = i; j <= Maxa; j += i)
            chkadd(sum[u][par][j], f[i]);
    }
    return ;
}
inline int solve(int rt) {
    dfs(rt, 0);
    int ret = 0;
    rep (i, l[rt], r[rt]) chkadd(ret, 1ll * dp[rt][0][i] * i % Mod);
    return ret;
}

signed main() {
    // freopen("samples//tree3.in", "r", stdin);
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    sieve();
    input();
    rep (i, 1, n) writln(solve(i));
    return 0;
}
/*

enumerate the root, define the status as f[node, number];

the complexity is too large, but if the node's father don't change, it's DP array won't change

save the father of the node in the DP array

but the memory limit? use vector.

\sum_{j}f(j)[(i,j)=1]

\sum_{j}f(j)\sum_{d\mid i,d\mid j}\mu(d)

\sum_{d\mid i}^n\mu(d)\sum_{d\mid j}f(j)

pretreat \sum_{d\mi j}f(j) --> the complexity O(m ln a)

*/

麻烦的杂货店 / Grocery

  显然求出前缀和,是一个一次变化 \(1\) 的图像,我们要求的是在同一区间中,划一条直线连接两个端点且中途函数图像不会跑到该直线以下的最长两端点距离。

  有一个 \(\mathcal O(qn)\) 的做法,单调栈即可,过程简单,就不阐释。想办法优化这个过程,实际上我们发现在单调栈做法中,我们只会在某个元素将要被弹出的时候才统计答案,也就是说,遇到第一个比它小的元素才会贡献(除非是挨着的情况),因为每次的变化量都为 \(1\),所以遇到第一个刚好比它小一的元素时,意味着前面已经有一个和它相同,因此我们找到了一个匹配点。但是每次都用单调栈做这个过程是十分低效的,前面已经分析过,实际上对于每个元素而言,单调栈中从左到右(或从右到左)遇到的第一个比它小 \(1\) 的元素才是有效的,因此我们可以找到一种方法将单调栈“存下来”,比较直观的方式是存下 往左边/往右边 第一个比它小 \(1\) 的元素的位置,但是这样依然不高效,我们依然要将所有的元素都遍历一遍。

  发现这个过程实际上有点像树上爬父亲的过程,一个点向第一个比它小 \(1\) 的位置连边,而这条边的权值为 \(|i-j|\),我们最后要找的是最长边的长度,因此不难想到使用倍增算法,于是这个题就这样被优化了,不过最后需要注意的是,当左右端点都不能跳了,说明它们到了这个区间的两个最低点,它们之间的距离也应当将答案更新一次。

/** @author Arextre */

#include <bits/stdc++.h>
using namespace std;

// #define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 1e5;
const int Logn = 17;

int n, m;
int f[Maxn + 5];
char s[Maxn + 5];

inline void input() {
    readin(n, m);
    scanf("%s", s + 1);
    rep (i, 1, n) f[i + 1] = f[i] + (s[i] == 'F'? 1: -1);
}

int tpl[Maxn + 5][Logn + 5];
int tpr[Maxn + 5][Logn + 5];
int mxl[Maxn + 5][Logn + 5];
int mxr[Maxn + 5][Logn + 5];
int stk[Maxn + 5], tl;
inline void prelude() {
    stk[tl = 1] = 1;
    rep (i, 2, n + 1) {
        for (; tl && f[stk[tl]] >= f[i]; --tl);
        tpl[i][0] = tl? stk[tl]: 0;
        mxl[i][0] = i - stk[tl] - 1;
        // fprintf(stderr, "tpl[%d, 0] == %d\n", i, tpl[i][0]);
        stk[++tl] = i;
    }
    stk[tl = 1] = n + 1;
    drep (i, n, 1) {
        for (; tl && f[stk[tl]] >= f[i]; --tl);
        tpr[i][0] = tl? stk[tl]: 0;
        mxr[i][0] = stk[tl] - i - 1;
        // fprintf(stderr, "tpr[%d, 0] == %d\n", i, tpr[i][0]);
        stk[++tl] = i;
    }
    rep (j, 1, Logn) rep (i, 1, n) {
        tpl[i][j] = tpl[tpl[i][j - 1]][j - 1];
        tpr[i][j] = tpr[tpr[i][j - 1]][j - 1];
        mxl[i][j] = max(mxl[i][j - 1], mxl[tpl[i][j - 1]][j - 1]);
        mxr[i][j] = max(mxr[i][j - 1], mxr[tpr[i][j - 1]][j - 1]);
    }
}

inline void solve() {
    int ql, qr;
    rep (_, 1, m) {
        readin(ql, qr), ++qr;
        int ans = 0;
        drep (j, Logn, 0) {
            if (tpr[ql][j] && tpr[ql][j] <= qr) {
                chkmax(ans, mxr[ql][j]);
                ql = tpr[ql][j];
            }
            if (tpl[qr][j] >= ql) {
                chkmax(ans, mxl[qr][j]);
                qr = tpl[qr][j];
            }
        }
        chkmax(ans, qr - ql); // DONT FORGET!!!
        writln(ans);
    }
}

signed main() {
    // freopen("samples//grocery3.in", "r", stdin);
    freopen("grocery.in", "r", stdin);
    freopen("grocery.out", "w", stdout);
    input();
    prelude();
    solve();
    return 0;
}
/**
 * find the line connect the same height
 * and the element between them are forbiddened to be strictly lower than this line
 * 
 * the valley will be ignored
 * use multiple to solve the problem
 * pretreat the 2^i-th position where the function value is lower than current
 * and the maximum value between the two position
 * when query, jump is okay
 * 
 * DONT FORGET THE FUCKING @p ql&qr AFTER JUMPING
*/
posted @ 2022-03-14 22:01  Arextre  阅读(35)  评论(0编辑  收藏  举报