模拟赛题解

4.25

CF838D Airplane Arrangements

Accepted
加一个点表示出发点,(最终这点有人也即非法),Ans = \(\frac{n + 1 - m}{n + 1} * (2(n + 1))^m\)
这一做法的正确性建立在环上的情况和题目中给出的情况一一映射

多校联训16

40+0+20+0
现在第一题都是签到题啊,虽然不少人能过,但是自己仍然A不掉,考试的时候要清醒一些
其实考试的时候都差不多想到正解了,不能轻易放弃啊

A.陌生的城市

就是根据如果将出现次数最多的字符都提出来,作为一个循环节为1的串,那么答案已经挺优了,然后发现更优的串数不会太多,直接搜出来用子序列自动机判一下就好
字符集 \(\leq 3\),因此长度为 \(x\) 的串中,出现次数最多的字符出现次数一定 \(\geq \left \lceil \frac{x}{3} \right \rceil\),注意那个上取整的符号,
因为是上取整,所以可以解出来循环节长度 \(\leq 6\)(考场上没有发现上取整的,所以解出来是 \(\leq 9\)

同时发现如果一个循环节长度为 \(x\),那么贡献 \(k^2*x\) , 出现最多的字符出现 \(y\) 次,我们只取最多的这种字符,贡献为 \((y * k)^2 = k^2 * y^2\) ,
所以如果 \(y^2 > x\) , 那么这个循环节肯定也不优

B.熟悉的原野

其实之前一次联训做过几乎一样的题呀,网格图,某些点不能选,找到一种建管道的方案,使得每个可以选的格子上都有管道并且所有管道构成若干个不相交的环,然后某些格子有特殊价值。

考场上以为建图好建,就是卡在了赋费用的地方,结果改的时候发现建图也有问题。

黑白染色,对于每个可以选的格子,建出原点 \(v0\) ,行点 \(v1\) ,列点 \(v2\) ,对于黑点 \(S->v0\) , \(v0->v1\) , \(v1->v2\) , 白点 \(v1->v0, v2->v0, v0->T\)
因为每个格子度数都为 \(2\),所以 \(S->v0\)\(v0->T\) 的流量为 \(2\) ,费用为 \(0\)\(v0\)\(v1\) 之间的边流量为 \(2\)\(v0\)\(v2\) 之间的边流量为 \(2\),费用一会再说
注意,接下来的建图部分考试时候想错了,每个黑点向周围没被禁的白点建边,如果在同一行,那么黑的行点向白的行点建 \((1,0)\) ,否则黑的列点向白的列点建 \((1,0)\)
注意黑点和白点的之间再没有其他的边了,考试的时候建多了。

然后如果 \(S->T\) 流了一个流量,就说明一个黑格子连了个管道和周围的某个白格子联通了,最终最大流等于总的未被禁的格子数才有解

注意 \(v0\)\(v1、v2\) 之间的费用,发现如果一个是村庄的格子, \(v0\)\(2\) 个流量全去了 \(v1\) 或者 \(v2\) ,那么就会贡献 \(1\) 的费用,因此我们可以在 \(v0\)\(v1\) 之间连 \(2\) 条边,分别为 \((1,0)\)\((1,1)\)\(v0\)\(v2\) 之间同理
这样只有 \(v0\)\(2\) 条都走向同一个点,才会产生 \(1\) 的费用、

C.美丽的世界

(待改,没写过闵可夫斯基和)
将装备看成 \((A_{x_i} , B_{y_i})\) 之间的有向边,
对于每个联通块讨论边方向,得到一些点,最优解一定是下凸包上的点,
对于每个联通块的下凸包求闵可夫斯基和得到总体的下凸包,遍历下凸壳算出答案。

D.大原题

将点按时间拆成 \(n*m\) 个点,每个点 \(i\) 的各个时刻之间串起来,流量为 \(a_i\)\(S\) 向每个点的 \(1\) 时刻点建流量 \(1\) 的边, \(1\)\(m\) 时刻点向 \(T\) 连一条流量为 \(a_1\) 的边
然后每时刻交换的操作,给该时刻的两点之间连一条流量为 \(1\) 的双向边,最终 \(S\)\(T\) 求个最大流就好。

但是因为点数太多,所以可以将一些没用的链略去,直接保存一些有用点即可,总点数 \(2m+2\)\(2m+3\) (如果 \(1\)\(m\) 时刻的点需要新建的话)

多校联训17

即得

定义f[S]表示联通性为S的点的图的最小权值和

\[f[S] = \min\limits_{x\subseteq S}f[S \backslash {x}] + g[x][S \backslash {x}] \]

g[x][S]表示 x 到联通块 S 中任意一个点的最短距离(不能经过 S 和 x 之外的点,也就是 x 走一步到达 S),这里 \(x \nsubseteq S\)

\[g[x][S] = \min\limits_{y\subseteq S} w[x][y] \]

这样可以 \(2^n*n^2\) 直接算出 \(g\) ,然后 \(2^n*n\) 算出 \(f\) ,对 \(f\) 做个超集 \(MIN\)(高维后缀和)就好了
但是求 \(g\) 时间复杂度太高,其实可以递推去求

\[g[x][S] = \min\limits_{y \subseteq S}(g[x][S \backslash {y}], w[x][y]) \]

对于 \(1\)\(x\) ,随便选一个 \(y\) 去更新就好了,注意初始化 \(g[x][\varnothing] = 2147483647\) 方便递推,然后求出 \(g\) 后再改为 \(0\) 来求 \(f\)
这样求 \(g\) 的复杂度也是 \(2^n*n\) 的了,总复杂度 \(\Theta (2^n*n)\)

易见

平凡

多校联训18

今天教练说快夏令营了,为了适应夏令营的赛制,所以今天IOI赛制,结果3道题有2道原题(不过后一道是以前没做过的)
而且可能是题比较简单容易A掉(没有涉及到难的知识点或者数学,唯一一道数学题T1,还是原题)
所以在18:30就改完了全过了,之所以没有改完是因为T2是水过去的,就是暴力提前终止

A.清风

skyh讲的原题,就是本文章开头的那一道,添一个起点,变成环,每次选从出发点开始的一段弧,然后用合法的方案数的比例×总方案数就好了。
考试的时候15分钟左右就写出式子了,不过一直拖到50分钟才交的,因为突然不会求那个不合法的方案数的占比了(害怕A太早下午要讲,自己又讲不出来)
其实就是只要选到出发点那个点(也包括了某一方向下后x个景点有超过x个人选),方案就不合法,其实一共有 \(2*(n+1)\) 个选择,我们可以看成选一个景点(任意方向)
就把它删去,选到出发点就不合法
列出式子就是第一个人选到出发点概率+第一个人未选到×第二个人选到+第一个人未选到×第二个人未选到×第三个人选到+...
\(\frac{2}{2n+2} + \frac{2n}{2n+2} * \frac{2}{2n} + \frac{2n}{2n+2} * \frac{2n-2}{2n} * \frac{2}{2n-2} + ... = \frac{m}{n+1}\)
这是不合法方案的占比,因为删一个景点就少2个选择,所以分母每删一个景点就少2

B.半夜

水过的,搞明白正解再写

C.鸣蝉

(其实就是四毛子算法的例题,LOJ原题)
loj6499
分块,每块用 \(bitset\) ,然后 \(ST\) 表合并各个块。
要手动开优化,并且缩小 \(bitset\) ,才能过
\(k\) 为块长,经实践最后块长取的 \(700\)\(bitset\) 缩到 \(5e4\)

默认询问区间个数与n同阶
时间复杂度为 \(\Theta (\frac{n^2}{w} + \frac{n^2log\frac{n}{k}}{kw} + nk)\)
空间复杂度为 \(O(\frac{n^2log\frac{n}{k}}{kw})\)

衡八联考3

文件路径

特殊边只有两类边

  • 可以走 无限次 的反祖边
  • 只能 走一次 的任意边
    如果需要加特殊边的话,目标文件一定是在上面任意一类边的终点的子树内,列出式子移个项,\(n^2\) 维护就好了

拔河

将选手看作有边权的边,连接左边 \(l_i\) 和右边 \(r_i\),每个联通块必须是个基环树,否则一定不满足题意。
对于两组权值之差不超过 K ,移个项得到对其中一个的限制,权值和为 S ,那么任意一组权值和应该满足 \([\lceil\frac{S-K}{2}\rceil,\lfloor\frac{S+K}{2}\rfloor]\)
对于环以外的部分贡献是确定的,环内的边权只有两种方向,可以直接 bitset 优化背包,算出可以拼出哪些权值和,复杂度 \(\mathcal{O}(\frac{nS}{\omega})\)
可以优化,因为 \(1 \leq v_i \leq 20\),所以算一下发现每次往背包中放的只有 \(O(\sqrt{n})\) 种权值,所以可以二进制优化多重背包(先选小的,差值可以选也可以不选),复杂度 \(\mathcal{O}(\frac{\sqrt{S}(log\sqrt{S})S}{\omega})\)

花绳

多校联训21

A.图

(CF1186F)

部分分提示了欧拉回路,考试的时候主要没想到如何处理度数为奇数的点。
其实就是把这些度数为奇数的点向虚点0建条边
因为总度数和是偶数,除0外的点度数和为偶数了,相减得到0度数也为偶数,存在欧拉回路
直接跑出来欧拉回路,保留奇数位置上的边(如果不是虚边),另外如果一条边在偶数位置上并与虚边相邻,则它不删(这种保留的边不超过n/2)。

(另外注意CF原题上不保证图联通,对于每个联通块进行一次这种操作)

B.询问

C.模法

\[f_n = \sum_{i=1}^n f_{n\%i} = \sum_{i=1}^n f_{n-\left \lfloor\frac{n}{i}\right \rfloor * i} \]

对于 \(i\) 根号分治
\(i < \sqrt{n}\) 暴力转移 \(O(\sqrt{n})\)
\(i > \sqrt{n}\) ,发现 \(\left\lfloor \frac{n}{i}\right\rfloor\) 只有 \(O(\sqrt{n})\) 种取值,每种对应的 \(i\) 是一段连续的
假设 \(i\) 取值 \([l,r]\) , \(\left\lfloor \frac{n}{i}\right\rfloor\) 取值恒为 \(A\)
\(n - \left\lfloor \frac{n}{i}\right\rfloor * i\) 是一段等差数列
首项 \(n-l*A\) , 公差 \(-A\) ,末项 \(n-r*A\) ,然后发现末项是数列中最小的一项,不用管了

于是维护 \(g[i][j]\) 表示首项 \(i\) ,公差 \(-j\)\(x\)\(f_x\) 之和
枚举 \(n\) ,求 \(f_n\) ,首先暴力转移 \(\sqrt{n}\) 以内的,再枚举 \(A\) ,算出对应的 \(l,r\)\(f_n += g[n-l*A][A]\) 即可,每求出一个 \(f_n\) ,更新 \(g[n]\)

多校联训22

A.矩阵空间

因为 \(n,m\) 同阶, \(m\)\(n\) 代替
一个显然的思路是对于每种颜色,算出每个点算出被几个矩形覆盖,枚举颜色 \(O(c)\) ,然后扫描线 \(O(nlogn)\) ,时间复杂度 \(O(cnlogn)\)
又双叒叕是根号分治,对于每种颜色,假设其矩形个数为 \(S\)
\(S \geq \sqrt{n}\) ,跑上面的算法,因为这种颜色数 \(\leq \sqrt{n}\) ,复杂度 \(O(\sqrt{n}nlogn)\)
\(S < \sqrt{n}\) ,(不能与点的个数 \(n\) 有关), 颜色数 \(\frac{n}{S}\),我们\(O(S^2)\) 枚举两两交集,更新交集范围内的点,交集的矩形一共有 \(\frac{n}{S}*S^2 = n*S\) 个,记录下所有这样的矩形,最后再跑个扫描线统一更新,复杂度 \(O(nSlogn) = O(n\sqrt{n}logn)\)

B.王道征途

之前考过 \(2\) 次,都是矩阵树定理+高斯消元,复杂度 \(O(n^4)\)
本题 \(n \leq 2000\) ,树形dp+二项式反演,复杂度 \(O(n^2)\)

C.斩尽牛杂

区间本质不同字串长度和\(sam+lct\) ,还没改
或许可以先做做 \(luogu\)区间本质不同字串个数

多校联训23

A.求和

将组合数转成下降幂,用第一类斯特林数转成通常幂,然后二项式定理展开,交换求和号,将 \(i\) 提前,与 \(a_i\) 一起维护
单次询问就是 \(O(klogn+k^2)\) 的,单次修改是 \(O(klogn)\) 的,所以总复杂度 \(O(mklogn)\)
好不容易自己推出个推式子题,下面具体写写:
我们要求 \(\sum\limits_{i=l}^{r}a_i\binom{r-i+k-1}{k-1}\)

\[\sum\limits_{i=l}^{r}a_i*\binom{r-i+k-1}{k-1} \]

\[=\sum\limits_{i=l}^{r}a_i*\frac{(r-i+k-1)^{\underline{k-1}}}{(k-1)!} \]

考虑 \((r-i+k-1)^{\underline{k-1}}\)

\[(r-i+k-1)^{\underline{k-1}} \]

\[=\sum\limits_{j=0}^{k-1}\begin{bmatrix}k-1\\j\end{bmatrix}(-1)^{k-1-j}(r-i+k-1)^{j} \]

\(f[i]=\begin{bmatrix}k-1\\i\end{bmatrix}(-1)^{k-1-i}\)

\[=\sum\limits_{j=0}^{k-1}f[j]\sum\limits_{l=0}^{j}\binom{j}{l}(-i)^{l}(r+k-1)^{j-l} \]

\[=\sum\limits_{l=0}^{k-1}(-i)^{l}\sum\limits_{j=l}^{k-1}f[j]\binom{j}{l}(r+k-1)^{j-l} \]

原式即为 \(\frac{\sum\limits_{i=l}^{r}a[i]\sum\limits_{l=0}^{k-1}(-i)^{l}\sum\limits_{j=l}^{k-1}f[j]\binom{j}{l}(r+k-1)^{j-l}}{(k-1)!}\)
数状数组维护 \(l\in [0,k-1]\)\(a_i*(-i)^{l}\)的和,然后查询时对于每个 \(l\),枚举 \(j\) 然后相乘累加答案,最后别忘乘 \(\frac{1}{(k-1)!}\)
修改就枚举 \(l\),修改 \(k\)

B.掉落

扫描线从上往下扫描,对于每个高度维护各个位置上有几个,是哪些高度开始下降的,从上往下扫的时候, KDTree 维护一个二维的平面
因为只会用到每个挡板 l-1r+1 位置的点,以及高度为 h+1w 个点,最开始将所有点都先加进去,然后支持矩形求和,矩形覆盖,单点修改即可
有一个很有效的剪枝,在 KDTree 操作的时候,如果当前区间权值和为 0return
因为每次分裂,最多只会多出 1 个有值的点,所以最后有值的点数是 2n 个,所以会有不少空点(近一半)

C.通信

计算几何,二分

NOI2021模拟赛3(hzoi)

本次考试代码十分好写+无数据结构+数据过水,导致我改完了3道题

排列

将每个数除掉平方因子后,只需要满足排列的任意相邻两个数不相等
相当于是有 \(c_1个a_1,c_2个a_2,c_3个a_3...\) ,每个数有唯一标号(权值相同但标号不同也算不同),相邻的数值不能相同的排列方案数
这是类经典的问题,叫做 多重集合交错排列,可以容斥 \(n^2\) 做。
我们只需要知道存在至少i个非法相邻关系的方案数即可(考场上没想到怎么求),定义此为 \(g_i\),最终答案即为 \(\sum\limits_{i=0}^{n-1}(-1)^{i}*g_i*(n-i)!\)
我们可以将 n 个数分为 n-i 块,每块必须有数,并且数值都相同,然后任意排列这些块就好了。
解释一下,分为 n-i 块,那么就已经产生了 i 组非法相邻关系,任意排列可能产生新的非法相邻关系,所以就是至少 i 组了
可以 dpf[i][j] 表示前 i 种数,已经分了 j 块的方案数(注意这里块内也是有序的)
\(f[i][j] = \sum\limits_{k=1}^{min(j,cnt_i)}f[i-1][j-k]\binom{cnt_i-1}{k-1}\frac{cnt_i!}{k!}\)
\(cnt_i!\) 因为块内也是有序的,除掉 \(k!\) 因为块间是无序的(因为一会要任意排列这些块), \(g_i\) 就是 f[tot][n-i]tot是数的种类总数
复杂度 \(\mathcal{O}(n\sqrt{a}+n^2)\)

路线

简单计算几何+简单dp 就可以 \(\mathcal{O}(n^3)\) 水过了

游戏

我们可以知道的信息就是

  • 每个人是否睡着了
  • 是在哪一天睡着的

最多 \(min(n-1,p)\) 个人睡着
所有方案为 \(\sum\limits_{i=0}^{min(n-1,p)}\binom{n}{i}d^{i}\)
然后这个上界是可以达到的,考虑对于第k个方案,设第k桶是酒
对于一个人,如果没睡觉,那么他就不喝第k桶,如果睡觉了就让他在喝第k桶后睡觉。
让最后醒着的人判断哪桶是酒。睡觉方案和酒的方案是可以一一对应的。
组合数要预处理,对于一个组合数,要先约分,再统一乘起来,处理单个的是 \(\mathcal{O}(p^2)\) 的。
总复杂度为 \(\mathcal{O}(p^3logn+pq)\)

多校联训24

5.25

排列游戏

[AGC010E] Rearranging

首先有不互质的数字当初始序列给定后,相对位置是不变的,我们给他们连上边
第一个人的作用是可以卡住一些小的数,把它放在与它相关的数的前面。
第二个人的作用是按照拓扑序取数,每次会取最大的数
sort后,从1n遍历,遇到未访问的就访问这一整个联通块(只访问未访问过的),连上边
建完所有的边之后,用个优先队列挨个取数,每次取最大的即可

使者

求出dfn序后发现就是一个单点修改,矩形求和,树状数组套权值线段树维护,复杂度 \(\mathcal{O}(nlog^2n)\)

折线

[AGC017F] Zigzag

直接dpf[i][S],前i个线,第i个线状态是S,枚举上一个线的状态转移,复杂度 \(\mathcal{O}(nm2^{2n})\)

发现瓶颈是要枚举相邻两个线的状态,考虑只枚举1
定义f[i][j][S]表示第i个线,已经走了j步,能走的最靠左的状态是S的方案数(向左0,向右1),S中前j位是第i个线前j步走的,后n-1-j位是i能走的尽量的靠左的状态

转移的时候枚举状态i,j,S
j+1位开始如果S有一段都是向右走的状态,那么只能向右走,f[i][j][S]贡献到f[i][j+1][S]
如果到了第p位,S0(可以向左),我们就讨论线ip的走向
向左,f[i][p-1][S]贡献到f[i][p][S],因为向左走了之后最左的路线不变
向右,f[i][p-1][S]贡献到f[i][p][S'],向右走后,路线变成了S‘,就是从当前点向右走一步,然后一直向左走直到遇上S,后面就都是S了,这个状态是S’(为什么遇上S后,后面都是S,因为我们是让S的方案数来作贡献),这个S‘可以用S通过位运算得到。

总结一下,每步两个方向,向左和向右
向左就直接转移(状态不变)
向右就要看作贡献的状态这一步是0/1,是1直接转移(状态不变),是0就改一下目标状态。

至于给定的限制,转移的时候判一下就好。
可以滚动数组优化掉前两维,因为都是i->i+1,j->j+1,所以直接压成f[2][S]即可。
还有点卡常,写的时候稍微注意下memset,然后少数组寻址,最后没办法了试了下加个取模优化(inline int)就快了近0.2秒(不知道是inline的原因还是O2下取模优化函数比较快的原因)

折线
#include <cstdio>
#include <cstring>
using namespace std;

#define lb(x) ((x) & (-(x)))

const int N = 21, M = 1000000007;

int n, m, K, mxs, now, las = 1, Ans;
int a[N][N], f[2][1 << 19];

inline int Add(int x, int y) { // fast!!!
	return (x += y) >= M ? x - M : x;
}

int main() {

	memset(a, -1, sizeof(a));
	scanf("%d%d%d", &n, &m, &K);
	--n, mxs = (1 << n) - 1;
	for(int i = 1; i <= K; ++i) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		a[x][y - 1] = z;
	}
	
	f[0][0] = 1;
	for(int i = 1; i <= m; ++i) {
		for(int j = 0; j < n; ++j) {
			now ^= 1, las ^= 1;
			memset(f[now], 0, 4 * (mxs + 1));
			int bit = 1 << j;
			int all = mxs ^ ((bit << 1) - 1);
			for(int s = 0; s <= mxs; ++s) {
				int v = f[las][s];
				if(!v) continue;
				if(a[i][j] != 1 && !(s & bit)) f[now][s] = Add(f[now][s], v);
				if(a[i][j] != 0) {
					int ss = (s & bit) ? s : ((s | bit) ^ lb(s & all));
					f[now][ss] = Add(f[now][ss], v);
				}
			}
		}
	}
	for(int s = 0; s <= mxs; ++s) (Ans += f[now][s]) %= M;
	printf("%d\n", (Ans + M) % M);
	
	return 0;
}

NOI2021模拟赛 4

5.27

三重串

找到规律,一个合法的串一定有两个回文中心x,y满足x+r[x]-1 >= y 且 y-r[y]+1 >= x (x<y),不同的(x,y)对应不同的合法串
哈希二分求出最长回文半径后用主席树维护,复杂度 \(\mathcal{O}(nlogn)\)

阿鲁巴

dp,矩阵快速幂,因为样例还没搞懂+没时间所以不改了

祭坛

我们可以发现答案具有单调性,x合法x-1一定合法,有一种二分+扫描线树状数组的 \(\mathcal{O}(nlog^{2}n)\) 的。
写了一种单调指针+扫描线线段树 \(\mathcal{O}(nlogn)\) 的做法。
这里ans1可以直接单调指针搞,初始化为0,扫描线扫每一列,不断检查ans+1,合法就++,这样扫描线部分nlog的复杂度,ans1只会加n
具体来说,扫描线维护的点x坐标相同,所以合法的点一定有个范围(这个点要满足下面上面都至少有ans1个点),
线段树上维护各个y值的点的信息,即该点左边右边点数的较小值,线段树支持查询区间max即可判断是否有合法点。
从左往右扫一遍得到ans1,固定ans1,从左往右再扫一遍,这个时候线段树上多维护个suml==r时,信息大于ans11,否则为0,支持区间求和即可求出ans2

多校联训26

排列

选一个k,将排列中大于k的设为1,否则设为0,只要序列b的每一位前缀和小于等于序列a的每一位前缀和,a就可以到达b,当然,这应该满足 \(\forall k \in [1,n]\)
状压dp,f[s]表示用了s状态这些数的方案数,我们知道s中1的个数c,即已经填了c位,讨论c+1位填什么数,还要保证对于 \(\forall k \in [1,n]\) ,sum都合法
然后发现2个性质
如果当前填了c位,c+1位填i

  • 对于k<i时前缀和合法,那么对于任意k都合法(因为k<i时i贡献1都合法,后来i贡献0那么肯定不会非法(尽管k大了导致标准前缀和也小了))。
  • 如果填i不合法,那么填大于i的数肯定不合法

从小到大枚举填的数i,i=1时一定合法,然后我们只需要保证在填i+1的时候对于k=i合法就好了,维护个sum就行,不合法就break
复杂度 \(\mathcal{O}(n*2^{n})\)

Treap

线段树合并,对值域开线段树,root[x]的线段树上下标v的信息为如果有个祖先权值为v,x的子树最多贡献几个节点。
线段树合并,维护区间max,线段树上二分(二分出修改区间),区间加1,单点查询,复杂度 \(\mathcal{O}(nlogn)\)

K-Beautiful Tree

Dp,容斥

多校联训27

5.29

新年快乐!

分块,块内排序,复杂度 \(\mathcal{O}(n\sqrt{n}logn)\)

哈密尔顿路

预设dp,要得到一个1~n的排列,从小到大放,定义f[i][j][k],表示放了前i个数,有j个'>'后面是不合法的(小的数)(如果末尾的是'>'的话就不算),末尾是k。
每次放i+1,先讨论其字符是'<'还是'>',然后三种情况

  • 放结尾
  • 放不合法的‘>’后面(即j个位置)
  • 合法的'>'后面

复杂度 \(\mathcal{O}(n^3)\)
优化,第三维为0/1表示'<'/‘>’,正着dp一遍,倒着dp一遍,两个dp数组拼起来就好了
复杂度 \(\mathcal{O}(n^2)\)

代码
#include <cstdio>
#include <cstring>

const int N = 5e3 + 10, M = 1e9 + 7;

int n;
int a[N], sum[N], f[N][N][2], g[2][N][2], Ans[N];

char s[N];

inline int Add(int x, int y) {
	return (x += y) >= M ? x - M : x;
}

int main() {
	freopen("path.in","r",stdin);
	freopen("path.out","w",stdout);
	
	scanf("%s", s + 1);
	n = strlen(s + 1);
	for(int i = 1; i <= n; ++i) {
		a[i] = (s[i] == '>');
		sum[i] = sum[i - 1] + a[i];
	}
	f[0][0][1] = f[1][0][a[1]] = 1;
	for(int i = 1; i < n; ++i) {
		for(int j = 0; j <= sum[i]; ++j) {
			for(int k = 0; k <= 1; ++k) {
				int v = f[i][j][k], c = sum[i] - j - k + 1;
				if(!a[i + 1]) {
					if(k) (f[i + 1][j][a[i + 1]] += v) %= M;
					if(j) f[i + 1][j - 1][k] = (f[i + 1][j - 1][k] + 1ll * v * j) % M;
					f[i + 1][j][k] = (f[i + 1][j][k] + 1ll * c * v) % M;
				}
				else {
					if(k) (f[i + 1][j][a[i + 1]] += v) %= M;
					f[i + 1][j][k] = (f[i + 1][j][k] + 1ll * v * j) % M;
					f[i + 1][j + 1][k] = (f[i + 1][j + 1][k] + 1ll * c * v) % M;
				}
			}
		}
	}
	g[n&1][0][0] = g[n&1][0][1] = 1;
	for(int i = n; i >= 1; --i) {
		int x = i & 1, y = x ^ 1;
		for(int j = 0; j <= sum[i]; ++j) Ans[i] = (Ans[i] + 1ll * g[x][j][a[i]] * f[i - 1][j][1]) % M;
		memset(g[y], 0, sizeof(g[y]));
		for(int j = 0; j <= sum[i]; ++j) {
			for(int k = 0; k <= 1; ++k) {
				int v = g[x][j][k];
				if(!a[i]) {
					g[y][j + 1][k] = (g[y][j + 1][k] + 1ll * v * (j + 1)) % M;
					g[y][j][k] = (g[y][j][k] + 1ll * (sum[i - 1] - j - k + 1) * v) % M;
				}
				else {
					g[y][j][k] = (g[y][j][k] + 1ll * v * j) % M;
					if(j) g[y][j - 1][k] = (g[y][j - 1][k] + 1ll * (sum[i - 1] - (j - 1) - k + 1) * v) % M;
				}
			}
		}
	}
	for(int i = 1; i <= n; ++i) printf("%d ", (Ans[i] + M) % M);
	return 0;
}

GT 的游戏

posted @ 2021-05-28 18:40  liuzhaoxu  阅读(151)  评论(0编辑  收藏  举报