首页 > 其他分享 >loj#575. 「LibreOJ NOI Round #2」不等关系

loj#575. 「LibreOJ NOI Round #2」不等关系

时间:2024-05-22 16:08:07浏览次数:13  
标签:cap NOI LibreOJ loj sum texttt sign int cases

记事件 \(A\) 为「当 \(s_i = \texttt<\) 时 \(p_i < p_{i + 1}\)」,事件 \(B\) 为「当 \(s_i = \texttt<\) 时 \(p_i < p_{i+1}\),且存在 \(s_j = \texttt>\),满足 \(p_i < p_{i+1}\)。所求即 \(n(A) - n(B)\)。

\(n(A)\) 是好求的,相当于部分定序排列,记每个递增段的长度为 \(a_1, a_2, \dots, a_k\),则 \(n(A) = \dfrac{n!}{\prod_{i=1}^ka_i!}\)。

\(n(B)\) 可以容斥地求,设有 \(m\) 个 \(\texttt>\),\(E_i\) 表示第 \(i\) 个 \(\texttt>\) 满足 \(p_i < p_{i+1}\),则有 \(n(B) = \sum\limits_{j=0}^n(-1)^j\sum\limits_{i_1, i_2, \cdots, i_j}n(E_1 \cap E_2 \cap \dots \cap E_j)\)。

考虑用 DP 把前后两次容斥放到一起做。

发现 \(n(E_1 \cap E_2 \dots \cap E_j)\) 实际上就是特殊的 \(n(A)\)(有部分 \(\texttt>\) 被钦定为 \(\texttt<\)),所以 \(n(A)\) 和 \(n(B)\) 中都会有 \(n!\) 这个系数,所以显然最后的答案里也会有,不妨把 \(n!\) 提出来。

设 \(i! \cdot f(i)\) 表示长度为 \(n\) 的合法串数(带容斥系数),答案即 \(n!\cdot f(n)\)。

考虑转移,我们可以任选前面的任意一个 \(\texttt>\),并把它后面的所有 \(\texttt>\) 都钦定为 \(\texttt<\),于是产生了一个新的递增段,统计方案数的变化。

至于为什么不把当前选定的 \(\texttt>\) 也钦定为 \(\texttt<\),那是因为如若钦定,则原来它分割的两个递增段会连到一起,但我们并不知道前一个递增段的起点,所以无法转移了。

但是有一个遗漏的情况,即把所有的 \(\texttt>\) 都钦定为 \(\texttt<\)。把 \(s_0\) 也看作 \(\texttt>\) 然后正常转移即可。

于是写出转移方程(注意我们已经提了分子 \(n!\) 了,考虑分母即可):

\[f(i) = \begin{cases} 1 & i = 0 \\ \sum\limits_{j=0}^{i-1}[s_j \ne \texttt<](-1)^{cnt_{i-1} - cnt_j}\dfrac{f(j)}{(i-j)!} & i \ge 1\end{cases} \]

其中 \(cnt_i\) 为 \(s_1, s_2, \dots s_i\) 中 \(\texttt>\) 数量。

时间复杂度 \(\mathcal O(n^2)\)。

提出一个 \((-1)^{cnt_{i-1}}\) 的系数来,设其为 \(p_i\),再令 \(sign_j = \begin{cases} (-1)^{cnt_j} & s_j \ne \texttt< \\ 0 & s_j = \texttt< \end{cases}\),则转移方程还可以写成:

\[f(i) = \begin{cases} 1 & i = 0 \\ p_i\sum\limits_{j=0}^{i-1}sign_jf(j)\dfrac1{(i-j)!} & i \ge 1 \end{cases} \]

不难看出这是一个卷积形式,分治 NTT 优化即可,时间复杂度 \(\mathcal O(n \log^2 n)\)。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 1 << 18, MOD = 998244353;

string s; int n, sign[N], p[N];
ll fct[N], ifct[N], f[N], G[2][18];

ll qp(ll base, int e) {
	ll res = 1;
	while (e) {if (e & 1) res = res * base % MOD; base = base * base % MOD; e >>= 1;}
	return res;
}

namespace Poly {
	int len, bits, rev[N];

	void NTT(ll *A, bool I = 0) {
		for (int i = 0; i < len; i++) if (i < rev[i]) swap(A[i], A[rev[i]]);
		for (int i = 1; i < len; i <<= 1) {
			ll wn = G[I][__builtin_ctz(i)];
			for (int j = 0; j < len; j += (i << 1)) {
				ll w = 1;
				for (int k = j; k < j + i; k++) {
					ll t = w * A[k + i] % MOD;
					A[k + i] = (A[k] - t + MOD) % MOD, A[k] = (A[k] + t) % MOD;
					w = w * wn % MOD;
				}
			}
		}
	}
	void INTT(ll *A) {
		NTT(A, 1); ll ilen = qp(len, MOD - 2);
		for (int i = 0; i < len; i++) A[i] = A[i] * ilen % MOD;
	}

	void mul(ll *A, ll *B, ll *res, int na, int nb) {
		len = 1, bits = -1; while (len <= na + nb) len <<= 1, bits++;
		fill(A + na + 1, A + len, 0), fill(B + nb + 1, B + len, 0);
		for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bits);
		NTT(A), NTT(B);
		for (int i = 0; i < len; i++) res[i] = A[i] * B[i] % MOD;
		INTT(res);
	}
}

ll A[N], B[N];
void cdq(int l, int r) {
	if (l == r) {f[l] = f[l] * p[l] % MOD; return;}
	int mid = (l + r) >> 1; cdq(l, mid);
	for (int i = l; i <= mid; i++) A[i - l] = f[i] * sign[i] % MOD;
	for (int i = l; i <= r; i++) B[i - l] = ifct[i - l];
	Poly::mul(A, B, A, mid - l, r - l);
	for (int i = mid + 1; i <= r; i++) f[i] = (f[i] + A[i - l]) % MOD;
	cdq(mid + 1, r);
}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);

	fct[0] = fct[1] = ifct[0] = ifct[1] = 1;
	for (int i = 2; i < N; i++) ifct[i] = (MOD - MOD / i) * ifct[MOD % i] % MOD;
	for (int i = 2; i < N; i++) fct[i] = fct[i - 1] * i % MOD, ifct[i] = ifct[i] * ifct[i - 1] % MOD;
	for (int i = 0; i < 18; i++) G[0][i] = qp(3, (MOD - 1) / (1 << (i + 1))), G[1][i] = qp(G[0][i], MOD - 2);

	cin >> s; n = s.length() + 1; s = '\0' + s;
	f[0] = sign[0] = p[0] = 1;
	for (int i = 1; i <= n; i++) {
		p[i] = sign[i - 1];
		sign[i] = s[i] == '>' ? MOD - sign[i - 1] : sign[i - 1];
	}
	for (int i = 1; i <= n; i++) if (s[i] == '<') sign[i] = 0;
	cdq(0, n);
	cout << fct[n] * f[n] % MOD;
	return 0;
}

标签:cap,NOI,LibreOJ,loj,sum,texttt,sign,int,cases
From: https://www.cnblogs.com/chy12321/p/18206488

相关文章

  • CSP历年复赛题-P1037 [NOIP2002 普及组] 产生数
    原题链接:https://www.luogu.com.cn/problem/P1037题意解读:一个长整数,有若干数字替换规则,计算可以转换成多少种不同的整数。解题思路:看题之后,第一感觉,是用DFS:1、用字符串存储整数2、用领接表存储数字替换规则,因为一个数字可以替换成多个其他数字3、在dfs中,枚举字符串每个数字......
  • CSP历年复赛题-P1002 [NOIP2002 普及组] 过河卒
    原题链接:https://www.luogu.com.cn/problem/P1002题意解读:从A(0,0)点走到B(n,m)点,只能向右或者向下,C点以及其控制点不能走。解题思路:根据题意,此题要么递归(DFS),要么递推(动态规划)先分析数据规模,最大从起点到终点要走40步,每个步有2种走法,一共240种路径,DFS会超时,且方案数必须用longlong......
  • CSP历年复赛题-P1042 [NOIP2003 普及组] 乒乓球
    原题链接:https://www.luogu.com.cn/problem/P1042题意解读:分别针对11分制和21分制,输出每局比分。只需要判断一局的结束条件:得分高者如果达到11或者21,且比分间隔大于等于2分,则表示一局结束,可开始下一局,用模拟法即可解决。100分代码:#include<bits/stdc++.h>usingnamespaces......
  • [NOIP2000 提高组] 单词接龙
    传送锚点:https://www.luogu.com.cn/problem/P1019题目描述单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和......
  • CSP历年复赛题-P1049 [NOIP2001 普及组] 装箱问题
    原题链接:https://www.luogu.com.cn/problem/P1049题意解读:装尽可能多的物品,使得总体积越大越好,即剩余空间最小,还是一个01背包问题,物品的体积就是其价值。解题思路:01背包模版题,物品体积、价值相同,直接采用一维dp。100分代码:#include<bits/stdc++.h>usingnamespacestd;co......
  • CSP历年复赛题-P1035 [NOIP2002 普及组] 级数求和
    原题链接:https://www.luogu.com.cn/problem/P1035题意解读:根据公式模拟法求解即可。解题思路:枚举i,计算sum,如果sum>k,则输出i100分代码:#include<bits/stdc++.h>usingnamespacestd;intmain(){intk;cin>>k;doublesum=0;inti=0;while(......
  • CSP历年复赛题-P1036 [NOIP2002 普及组] 选数
    原题链接:https://www.luogu.com.cn/problem/P1036题意解读:题目即要在n个数中,枚举出所有的子集,当子集中数字个数刚好为k时,求和,判断是否是素数。解题思路:方法一:二进制法通过二进制法,可以枚举一个集合中所有元素“选”或者“不选”的情况,用二进制1表示选该元素,二进制0表示不选。......
  • CSP历年复赛题-P1030 [NOIP2001 普及组] 求先序排列
    原题链接:https://www.luogu.com.cn/problem/P1030题意解读:已知中序、后序,求先序。解题思路:与洛谷题单指南-二叉树-P1827[USACO3.4]美国血统AmericanHeritage非常类似,不在介绍过程,直接给出代码。100分代码:#include<bits/stdc++.h>usingnamespacestd;stringin,post......
  • CSP历年复赛题-P1023 [NOIP2000 普及组] 税收与补贴问题
    原题链接:https://www.luogu.com.cn/problem/P1023题意解读:给定商品单价和对应销量表,计算使得采用预期价格销售得到最大利润时的最小补贴或者税收。解题思路:1、样例模拟31281303012031110-1-115政府预期价格:31商品成本:28,按成本价售卖销量:130商品单价:30,对应销量:120......
  • CSP历年复赛题-P1028 [NOIP2001 普及组] 数的计算
    原题链接:https://www.luogu.com.cn/problem/P1028题意解读:给定n,构造数列,可以用递归或者递推。解题思路:1、递归定义count(n)返回数列的个数  n==1时,count(n)=1  n!=1时,count(n)=1+count(1)+count(2)+...+count(n/2)注意,递归会导致大量重复计算,需要用一个hash......