[题解]可恶!然而......
\(\mathcal{Back\;To\;The\;Menu}\).
2022-02-26 可恶!然而......
卡在一道从未想过的题上面......
排队 / Queue
设 \(d(i)\) 表示 \(\sum_{j<i}[a_j>a_i]\),就是反序表那玩意,然后我们想求满足 \(\sum_id(i)=\sum_i\max(i-a_i,0)\) 的序列个数。
就每个位置而言,显然存在 \(d(i)\ge \max(i-a_i,0)\),因为 \(i-a_i\) 表示至少有多少个比它大的在它前面,而 \(d(i)\) 表示准确的比它大且在它前面的数字个数。因此,想让 \(\sum_id(i)=\sum_i\max(i-a_i,0)\) 成立,无非让每个位置都要满足 \(d(i)=\max(i-a_i,0)\),这个等式意味着什么?要么前面没有比它大的,要么所有比它小的都在它前面.
此时我们可以使用 DP,每增加一个位置,只可能有两种选择:填入比最大值还要大的数(前面没有比它大的),或者是前缀集合的 mex(不能算上 \(0\)),设 \(f(i,j)\) 表示前 \(i\) 个位置,最大值为 \(j\),存在转移:
它是一个前缀和的形式,记 \(g(i,j)=\sum_{k\le i}f(i,k)\),那么
发现最后我们将形式统一到了一个类似于网格图上走路的问题,每次可以向右或者向上走一步,最后走到 \((n,n)\) 的方案数,但是还有一个问题,当 \(i>j\) 时,\(g\) 实际上是不参与转移的,也就是说,我们中途还不能逾越 \(y=x\) 这条线,于是这就变成经典的卡塔兰数模型了,从输入的 \(m\) 个数中,我们可以得到最大值 \(\max\),最后就是算从 \((m,\max)\to (n,n)\) 中途不逾越 \(y=x\) 的方案数了。
/** @author __Elaina__ */
#include <bits/stdc++.h>
#include <cmath>
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 * 2;
const int Mod = 1e9 + 7;
int inv[Maxn + 5], fac[Maxn + 5], finv[Maxn + 5];
inline void prelude() {
fac[0] = inv[0] = fac[1] = inv[1] = finv[0] = finv[1] = 1;
rep(i, 2, Maxn) {
fac[i] = 1ll * fac[i - 1] * i % Mod;
inv[i] = 1ll * (Mod - Mod / i) * inv[Mod % i] % Mod;
finv[i] = 1ll * finv[i - 1] * inv[i] % Mod;
}
}
inline int C(int n, int m) {
if (n < m || n < 0 || m < 0)
return 0;
return 1ll * fac[n] * finv[n - m] % Mod * finv[m] % Mod;
}
inline int Cata(int n, int m) { return (0ll + C(n + m, n) + Mod - C(n + m, m - 1)) % Mod; }
int n, m, a[Maxn + 5];
signed main() {
freopen("queue.in", "r", stdin);
freopen("queue.out", "w", stdout);
prelude();
readin(n, m);
int tl1 = 0, tl2 = 0;
rep(i, 1, m) {
readin(a[i]);
if (a[i] <= i) {
if (a[i] < tl1)
return writln(0), 0;
tl1 = a[i];
} else {
if (a[i] < tl2)
return writln(0), 0;
tl2 = a[i];
}
}
tl2 = min(n - tl2, n - m);
writln(Cata(n - m, tl2));
return 0;
}
论文查重 / Thesis
这就是我说的那道奇怪的题......
一般的 LCS 思路,是 DP,设 \(f(i,j)\) 表示 \(T\) 匹配到 \(i\),\(S\) 匹配到 \(j\) 时,LCS 的长度,注意到 \(|S|\) 总共很大,不妨将 \(j\) 设为状态中储存的量,而将 LCS 的长度变成状态,所以有了一个新状态:\(g(i,j)\) 表示 \(T\) 匹配到 \(i\),当前 LCS 的长度为 \(j\) 时,\(S\) 至少匹配到哪里了,然后再进行转移即可。
仍然没有代码 😦
烽火戏诸侯 / Balefire
永神给出了一种贪心可以过掉,但是目前为止仍然不知道应该怎么证明。
先考虑将位置相邻的进行操作,直到无法操作为止,此时剩下的东西在坐标上应当是一个连续段,然后再考虑依次将坐标最大的和坐标和第三大、第四大、第五大......依次进行操作:
计算一下它的贡献,就完了。
个人感觉它是否有点像 [ARC126E]Infinite Operations 啊?