[题解]女神节

\[\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-03-08 女神节

  差点就连低保都吃不到了......从 \(\color{yellow}{\rm MLE}\) 的边缘把自己救活。

十 / Ten

  「终于,你来了。」

  高扬的尘灰,让 \(\sf OID\) 看不清风中那一袭披风之下究竟何方神圣,不过,听他这口气,似乎他已经在此等候许久。\(\sf OID\) 身为神祇已孤身漂泊江湖已久,现今江湖,知道祂的真实身份的人不过两种,其一,被祂锁在机房里面天天暴打,这种人最为可怜,他们不仅肉体封锁在机房之中无法动弹,灵魂上还要在一次又一次的考试中被 \(\sf OID\) 践踏,他们当然不会说出去 \(\sf OID\) 的身份,因为他们已经丧失神智,口中只有 “祂,祂,祂又来了,又来了!!!啊啊啊!!!”;其二,是那些在某次考试中直接被 \(\sf OID\) 踩爆的生物,他们就更惨,才第一面见到这世上唯一的真神,就尸骨无存,再也不能将神迹传与他说。当然,第二种情况在某次 \(\texttt {0xCBDD1}\) 事件之后便再无出现。

  由于这两者的存在,\(\sf OID\) 降世多年,江湖上也无神祇之语流传。

  \(\sf OID\) 仔细思考了一番,最终还是认为祂的身份世上无人知晓,便只将眼前之人当做一个平平无奇的挡路强盗 —— 这种人,祂手起刀落从不手软,宝剑入鞘便是人头落地之时。

  「兄弟,你怕不是认错人了吧?我好像并不认得你诶?」

  祂手握剑柄,将剑稍稍出鞘,那象征绝世神兵的闪耀穿透风沙,似君临天下,祂慢慢走向那袭披风未挡住的道路另一侧,想要从他身边绕过去。一步,又一步,终于,祂绕过了那个神秘人,稍稍呼出一口气,放下心中骇人的杀机,微微松手,宝剑便轻轻入鞘。此时的他,已经在祂的背后稍远处,苍穹地府之间,一人一神之隙,风停沙散,是绝世之战前天地的屏息。

  「不,你就是我等的人,或者说,神!」

  祂顿住脚步,瞳孔紧缩,呼吸急促,左手再一次悄悄握住剑柄,不过,不同的是,手触剑柄的一瞬,腾蛟起凤,紫电青霜,耀眼千里,剑已出鞘,神已降世。

  从祂的身后,再一次传来那如同丧钟般的幽语。

  「你不必知道我是如何知晓你的存在,毕竟,我将要弑神,天下将再无 \(\sf OID\),取而代之的,是我,小游!我将坐上神位,鞭笞天下!」

  那自名为小游的披风人瞬间动起来,不过眨眼间,便来到了 \(\sf OID\) 身后,他手中显出一柄大剑,顺势一挥。

  「十字斩!」

  \(\sf OID\) 俯身一挥,横剑相挡,却见那一斩如开天辟地,十字交叉,直取祂命......

  刚开始想了一个 DP,具体就是设 \(f(i)\) 表示前 \(i\) 个位置的总方案数,然后还要设 \(g(l,r)\) 表示最左边的点是 \(l\),当前区间的交的右边界是 \(r\) 时的集合数量,转移很简单,但是修改是一个二维的东西,总复杂度是 \(\mathcal O(n^2\log n)\sim \mathcal O(n^3)\) 的,后面我又把它魔改了一下使得它可以用树套树优化,然后就变成了一个时间空间复杂度均为 \(\mathcal O(n\log^2n)\) 的算法,然而树套树的空间需要 \(\rm 1.2G\) 左右......

  不妨从另外一个方面来想这个问题,上述的 DP 本质是枚举一个右端点进行转移,不妨先从一个更加朴素的方向入手:枚举选择的点集的左右端点 \(l,r\),那么在 \((l,r)\) 中,能够覆盖到 \(l,r\) 这俩点的点,也能够到达 \((l,r)\) 中的任意一个点,因此,我们找出在 \((l,r)\) 中能够覆盖 \(l,r\) 的所有点,记他们的数量为 \(c\),那么这一对端点对答案的贡献就是 \(2^c\).

  只是枚举左右端点复杂度就达到了 \(\mathcal O(n^2)\),要想个办法优化,对区间统计的一个经典处理就是扫描线 —— 我们扫描这个区间的左端点,然后用数据结构维护当前左端点到每个右端点之间的 \(c_i\).

  至于怎么维护,考虑一个点 \(i\),其右端点为 \(r_i\),显然可以直接选择 \(i\),所以要给位置 \(i\) 带来 \(+1\) 的贡献,同时,对于 \((i,r_i]\) 的右端点,显然在当前的区间中点 \(i\) 是可以选择的,它会给 \((i,r_i]\) 的右端点带来 \(\times 2\) 的系数。

  值得注意的是,我们应当在 \(l_i-1\) 处将 \(i\) 的贡献全部退掉。

/** @author __Elaina__ */

// #pragma GCC optimize("Ofast")

#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 repf(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(tag) (__builtin_popcount(tag))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define curse(...) fprintf(stderr, __VA_ARGS__)

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

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 = 2e5;
const int Mod = 998244353;
inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

int n;
int l[Maxn + 5], r[Maxn + 5];

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

namespace Subtask1 {

const int Maxn = 2000;

int f[Maxn + 5], g[Maxn + 5][Maxn + 5];

inline void launch() {
    rep (i, 1, n) {
        f[i] = (f[i - 1] + 1) % Mod;
        chkadd(g[i][r[i]], 1);
        rep (j, l[i], i - 1) rep (k, i, n)
            chkadd(f[i], g[j][k]);
        rep (j, l[i], i - 1) {
            rep (k, i, r[i]) g[j][k] = (g[j][k] << 1) % Mod;
            rep (k, r[i] + 1, n) chkadd(g[j][r[i]], g[j][k]);
        }
    }
    writln(f[n]);
}

} // namespace Subtask12

namespace Subtaskother {

vector<int> vec[Maxn + 10];

int sum[Maxn << 2 | 2], tag[Maxn << 2 | 2];

#define ls (i << 1)
#define rs (i << 1 | 1)
#define mid ((l + r) >> 1)
#define _lhs ls, l, mid
#define _rhs rs, mid + 1, r

void build(int l, int r, int i) {
    tag[i] = 1;
    if (l == r) return ;
    int m = l + r >> 1;
    build(l, m, ls);
    build(m + 1, r, rs);
}
void pushup(int i) { sum[i] = (sum[ls] + sum[rs]) % Mod; }
void work(int i, int c) {
    tag[i] = 1ll * tag[i] * c % Mod;
    sum[i] = 1ll * sum[i] * c % Mod;
}
inline void pushdown(int i) {
    if (tag[i] == 1) return ;
    work(ls, tag[i]), work(rs, tag[i]), tag[i] = 1;
}
void update(int pos, int c, int l, int r, int i) {
    if (l == r) return sum[i] = 1ll * c * tag[i] % Mod, void();
    int m = l + r >> 1;
    pushdown(i);
    if (pos <= m) update(pos, c, l, m, ls);
    else update(pos, c, m + 1, r, rs);
    pushup(i);
}
void update(int ql, int qr, int c, int l, int r, int i) {
    if (ql <= l && r <= qr) return work(i, c), void();
    int m = l + r >> 1;
    pushdown(i);
    if (m >= ql) update(ql, qr, c, l, m, ls);
    if (m < qr) update(ql, qr, c, m + 1, r, rs);
    pushup(i);
}
void update(int x) {
    update(x, 1, 1, n, 1);
    if (r[x] > x) update(x + 1, r[x], 2, 1, n, 1);
}
void revoke(int x) {
    update(x, 0, 1, n, 1);
    if (r[x] > x) update(x + 1, r[x], Mod + 1 >> 1, 1, n, 1);
}
int query(int ql, int qr, int l, int r, int i) {
    if (ql <= l && r <= qr) return sum[i];
    int m = l + r >> 1, ans = 0;
    pushdown(i);
    if (m >= ql) ans = query(ql, qr, l, m, ls);
    if (m < qr) chkadd(ans, query(ql, qr, m + 1, r, rs));
    return ans;
}

inline void launch() {
    int ans = 0;
    build(1, n, 1);
    for (int i = n; i; --i) {
        vec[l[i] - 1].push_back(i);
        while (!vec[i].empty()) {
            revoke(vec[i].back());
            vec[i].pop_back();
        }
        chkadd(ans, query(i, r[i], 1, n, 1));
        chkadd(ans, 1);
        update(i);
    }
    writln(ans);
}

}

signed main() {
    freopen("ten.in", "r", stdin);
    freopen("ten.out", "w", stdout);
    input();
    if (n <= 20) Subtask1::launch();
    else Subtaskother::launch();
    return 0;
}

二十 / Twenty

  祂跃起翻滚,一息间便再次与他拉开距离,远距离的作战是祂最擅长的,在敌人再一次向祂靠近的刹那,祂至少可以施展 \(835025\) 种不同的神术,不过,正当祂想要施法时,脚下那一片土地闪起明亮的光辉。

  「哈哈,你以为我不知道你那愚蠢的战术吗,你的一举一动,都在我的意料当中,我算出了向你贴近的时间,算出了你拔刀的速度,算出了你翻滚的距离,算出了你翻滚的角度与你的背之间所呈的夹角,最终,在你必定会落地施法的位置,布下了圣杀阵,不出所料,你的神座,是我的了!」

  \(\sf OID\) 心中一紧,祂暗自掐指一算,这一轮若他占 \(53\) 分,那么祂可能最多能占 \(3\) 分,这将是二十倍的差距,高手过招,招招致命,更何况这差的 \(50\) 分,最终可能让祂用生命来偿还,不过眼下别无他法,只见祂紧握剑柄,斩向大阵......

  这个题没有代码了,计算几何并不是特别想做。

  一个奇奇怪怪的结论:答案等于那个奇奇怪怪的凸包的周长。

  证明:设 \((x(\theta),y(\theta))\)\(\theta^\circ\in [0,2\pi)\) 时最外侧的点的坐标,这里的点是指切点,而非从原点出发最远的那个点。

\[\begin{aligned} (*)&=\int_{0}^{2\pi} \begin{bmatrix}x(\theta)\\y(\theta)\end{bmatrix}\cdot\begin{bmatrix}\cos\theta\\\sin\theta\end{bmatrix}\d\theta \\ &=\int_{0}^{2\pi}\brak{x\cos\theta+y\sin\theta}\d \theta \\ &=\int_{0}^{2\pi} x\d(\sin \theta)-\int_{0}^{2\pi} y\d(\cos\theta) \\ &={\Big[}x\sin\theta{\Big]}_{0}^{2\pi}-\int_0^{2\pi}\sin\theta\d x-{\Big[}y\cos\theta{\Big]}_{0}^{2\pi}+\int_{0}^{2\pi}\cos\theta\d y \\ &=\int_{0}^{2\pi}\cos\theta y'(\theta)\d\theta-\int_0^{2\pi}\sin\theta x'(\theta)\d\theta \\ &=\int_{0}^{2\pi}\begin{bmatrix}x'(\theta)\\y'(\theta)\end{bmatrix}\cdot \begin{bmatrix}-\sin\theta \\ \cos\theta\end{bmatrix}\d\theta \\ &=\int_0^{2\pi} \begin{vmatrix}\begin{bmatrix}x'(\theta)\\y'(\theta)\end{bmatrix}\end{vmatrix}\d\theta \\ &=C \end{aligned} \]

  不过有一点小区别,我们积分的时候算的其实只有卡壳俩直线距离的一半,因此真正的期望并不是 \(\displaystyle\frac{C}{2\pi}\),而是 \(\displaystyle\frac{2C}{2\pi}=\frac{C}{\pi}\),这也是为什么最后我们乘上一个 \(\pi\) 之后就变成图形的周长了。

  至于怎么找这 \(n\) 个点的凸包,直接用题解了。

  我们考虑分治,每次将所有点分成两部分(不需要按位置关系),然后我们考虑将两个凸包合并。

  由凸包可以得到,对于每个角度,哪个圆在最外侧。

  与此同时,如果你知道对于每个角度,哪个圆在最外侧,那你也可以直接得到凸包。

  所以我们考虑维护,对于当前点集,每个角度哪个圆在最外侧。

  那么分治的时候,我们只需要将这个信息合并一下,分治最底端单个点的情况就是每个角度都是这个点
在最外侧。

  对于一个角度,在最外侧的圆只有两种可能,也就是当前点集的两个子点集在这个角度最外侧的圆。

  那么我们只要对这两个圆做一下公切线,就可以得到每个角度,这两个圆哪个在更外侧。

七十 / Seventy

  \(\sf OID\) 最终破阵,但祂走出阵时,已体无完肤。直到步入阴影之中,祂才察觉他的威压,他背对着祂,提剑矗立,挡于身前,不染一点风沙,披风依旧一尘不染,血迹布满他的双手,但没有一丝沾染衣袖。他已经瓦解了祂的所有法术,卸除了祂的所有武器,破开了祂的所有防御阵法,现在的 \(\sf OID\),世间唯一的真神,在小游手下如同玩物,神の宝座,早已是他的瓮中之鳖。

  「你输了。」

  祂面容平静,仿佛一切都在祂的预料之中,祂缓缓开口,念出了那句小游后半生都将为之惊恐的术法。

  「劣化!」

  没有一丝拖泥带水,小游瞬间倒下,血管炸开,鲜血喷涌而出,没有任何办法可以阻止术法的蔓延,他看着他的生命走向尽头,却无能为力,他那恐惧、麻木、错愕的眼神,随着他的生命走向尽头,渐渐迷失......

  冥冥之中,他仿佛听见了祂的嘲笑。

  模糊之中,他仿佛听见了一群人的唉声叹气。

  清醒之中,他确是听见了一群人坐在电脑前发呆。

  「我,我不是已经死了吗?」

  他看着眼前明亮的机房,不知此为何处。却见讲台,小游转向他,微笑地说:

  「欢迎来到被囚者的机房,你是第七十号犯人。」

  ......

  用随机游走之后经典的转化之后,这就是一个带状矩阵的高斯消元,直接环带状矩阵暴力消元即可,每行有效元素 \(2k\) 个,每行需往下消 \(k\) 行,总复杂度 \(\mathcal O(nk^2)\).

  但是这样要超时,根据我们推测,可能的原因竟是大小为 \(4\) 的常数......还有一种方法,对于 \(2k\ge n\) 的情况,直接暴力做高斯消元,对于 \(2k<n\) 的情况,我们另起灶炉。

  一个神奇的想法是,我们设出前 \(2k\) 个位置的元,那么,可以递推求出 \((2k,n]\) 所有地方关于前 \(2k\) 个位置的表达式,然后你会发现,递推的时候前 \(k\) 个元素构成的等式和 \(n-k+1\sim n\) 这些位置构成的等式我们并没有用上,一共 \(2k\) 个方程,有 \(2k\) 个元,Done!

  不过还要加上一个方程,那就是 \(\displaystyle\sum p_i=1\),不然可能会解出来全是 \(0\).

/** @author __Elaina__ */

// #pragma GCC optimize("Ofast")

#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 repf(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
#define masdf(...) fprintf(stderr, __VA_ARGS__)
#define mEndl masdf("\n")

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

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 = 2e4;
const int Maxk = 50;
const int Mod = 998244353;
inline void chkadd(int& x, int y) { if ((x += y) >= Mod) x -= Mod; }

inline int qkpow(int a, int q) {
    int r = 1;
    for (; q; q >>= 1, a = 1ll * a * a % Mod)
        if (q & 1) r = 1ll * r * a % Mod;
    return r;
}

int n, k;
int pl[Maxn + 5][Maxk + 5];
int pr[Maxn + 5][Maxk + 5];

inline void input() {
    readin(n, k);
    repf (i, 0, n) {
        int sum = 0;
        drep (j, k, 1) readin(pl[i][j]), chkadd(sum, pl[i][j]);
        rep (j, 1, k) readin(pr[i][j]), chkadd(sum, pr[i][j]);
        sum = qkpow(sum, Mod - 2);
        rep (j, 1, k) {
            pl[i][j] = 1ll * pl[i][j] * sum % Mod;
            pr[i][j] = 1ll * pr[i][j] * sum % Mod;
            // masdf("Node %d:> tol == %d, tor == %d\n", i, pl[i][j], pr[i][j]);
        }
    }
}

namespace Subtask1 {

const int Maxn = 300;

int r, c;
vector<int> v[Maxn + 5], x;

inline void buildEqu() {
    r = n + 1, c = n + 1;
    repf (i, 0, r) v[i].resize(c + 1);
    repf (i, 0, n) {
        v[i][i] = Mod - 1;
        rep (d, 1, k) {
            int p = (i + n - d) % n;
            chkadd(v[i][p], pr[p][d]);
            p = (i + d) % n;
            chkadd(v[i][p], pl[p][d]);
        }
        v[i][c] = 0;
    }
    repf (j, 0, c) v[n][j] = 1;
    // repf (i, 0, r) {
    //     repf (j, 0, c) masdf("%d ", v[i][j]);
    //     Endl;
    // }
}

inline void gauss() {
    repf (k, 0, r) { /** @p r-1 variables in total */
        int cur = -1;
        repf (i, k, r) if (v[i][k]) cur = i;
        // assert(!~cur); // should've found one
        if (!~cur) { assert(k == r - 1); break; }
        if (cur != k) swap(v[cur], v[k]);
        int inv = qkpow(v[k][k], Mod - 2);
        repf (j, k, c) v[k][j] = 1ll * v[k][j] * inv % Mod;
        repf (i, 0, r) if (i ^ k) {
            if (!v[i][k]) continue;
            int coe = v[i][k];
            repf (j, k, c)
                v[i][j] = (v[i][j] + Mod - 1ll * coe * v[k][j] % Mod) % Mod;
        }
    }
    x.resize(c - 1);
    repf (i, 0, c - 1) x[i] = v[i][c - 1];
}

inline void launch() {
    buildEqu();
    gauss();
    repf (i, 0, n) printf("%d\n", x[i]);
    return ;
}

} // namespace Subtask1

namespace Subtaskother {

inline vset operator +(vset a, const vset& b) {
    repf (i, 0, (int)a.size()) chkadd(a[i], b[i]);
    return a;
}
inline vset operator -(vset a, const vset& b) {
    repf (i, 0, (int)a.size()) a[i] = (a[i] + Mod - b[i]) % Mod;
    return a;
}
inline vset operator *(vset a, int coe) {
    repf (i, 0, (int)a.size()) a[i] = 1ll * a[i] * coe % Mod;
    return a;
}
inline vset operator *(int coe, vset a) {
    repf (i, 0, (int)a.size()) a[i] = 1ll * a[i] * coe % Mod;
    return a;
}
inline void print(vset& x) {
    repf (i, 0, (int)x.size()) masdf("%d ", x[i]); mEndl;
}
int len;
vset cprs[Maxn + 5];

int r, c;
vset a[Maxk * 2 + 5];
inline void buildEqua() {
    c = k << 1 | 1;
    auto getEq = [](int id) {
        vset ret(len);
        rep (d, 1, k) {
            int p = (id + n - d) % n;
            ret = ret + pr[p][d] * cprs[p];
            p = (id + d) % n;
            ret = ret + pl[p][d] * cprs[p];
        }
        return ret;
    };
    repf (i, 0, k) {
        a[r] = getEq(i) - cprs[i];
        assert(a[r].size() == len);
        a[r].resize(c);
        a[r][c - 1] = 0;
        ++r; // a new equation
    }
    repf (i, n - k, n) {
        a[r] = getEq(i) - cprs[i];
        assert(a[r].size() == len);
        a[r].resize(c);
        a[r][c - 1] = 0;
        ++r;
    }
    // the last equation
    a[r] = cprs[0];
    repf (i, 1, n) a[r] = a[r] + cprs[i];
    assert(a[r].size() == len);
    a[r].resize(c), a[r][c - 1] = 1;
    ++r;
}

vset x;
inline void gauss() {
    repf (k, 0, r) {
        int cur = -1;
        repf (i, k, r) if (a[i][k]) cur = i;
        if (!~cur) { assert(k == r - 1); break; }
        if (cur != k) swap(a[cur], a[k]);
        int inv = qkpow(a[k][k], Mod - 2);
        repf (j, k, c) a[k][j] = 1ll * a[k][j] * inv % Mod;
        repf (i, 0, r) if (i ^ k) {
            if (!a[i][k]) continue;
            int coe = a[i][k];
            repf (j, k, c)
                a[i][j] = (a[i][j] + Mod - 1ll * coe * a[k][j] % Mod) % Mod;
        }
    }
    // repf (i, 0, r) print(a[i]);
    x.resize(len);
    repf (j, 0, len) x[j] = a[j][c - 1];
}

inline int calc(int id) {
    int ret = 0;
    repf (i, 0, len) chkadd(ret, 1ll * x[i] * cprs[id][i] % Mod);
    return ret;
}

inline void launch() {
    assert(n > k << 1);
    len = k << 1;
    repf (i, 0, n) cprs[i].resize(len, 0);
    repf (i, 0, len) cprs[i][i] = 1;
    repf (i, len, n) {
        int core = i - k;
        // masdf("Point i:> core == %d\n", core);
        // masdf("pl[%d, %d] == %d\n", i, k, pl[i][k]);
        int inv = qkpow(pl[i][k], Mod - 2);
        // masdf("inv == %d\n", inv);
        cprs[i] = cprs[core];
        repf (j, core - k, core) cprs[i] = cprs[i] - pr[j][core - j] * cprs[j];
        repf (j, core + 1, i) cprs[i] = cprs[i] - pl[j][j - core] * cprs[j];
        cprs[i] = cprs[i] * inv;
    }
    // masdf("The cprs:>\n");
    // repf (i, 0, n) print(cprs[i]);
    buildEqua();
    gauss();
    for (int i = 0; i < n; ++i)
        writln(calc(i));
}

} // namespace Subtaskother

signed main() {
    freopen("seventy.in", "r", stdin);
    freopen("seventy.out", "w", stdout);
    input();
    // Subtaskother::launch();
    if (n <= 300) Subtask1::launch();
    else Subtaskother::launch();
    return 0;
}
posted @ 2022-03-14 22:12  Arextre  阅读(60)  评论(0编辑  收藏  举报