「LibreOJ NOI Round #2」不等关系

解题思路

令 \(F(k)\) 为恰好有 \(k\) 个大于号不满足的答案,\(G(k)\) 表示钦点了 \(k\) 个大于号不满足,剩下随便填的方案数。

枚举有多少个大于号被钦点了,\(F(0)=\sum_{i=0}^n G(i)(-1)^i\) 。

对于一个只有小于号限制的序列的方案数就是每一个小于号链接的联通块里分配的数字顺序固定,块与块之间随便排,令 \(sz[i]\) 表示第 \(i\) 个联通块的大小,方案数也就是 $ \dfrac{n!}{\prod_{i=1}^msz[i]!}$

令 \(dp[i]\) 表示前 \(i\) 个数,\(s_{i}\) 不强制改为小于号的 \(\prod_{i=1}^m (-1)^m \dfrac{1}{sz[i]!}\) 乘上容斥系数之和之和,令 \(p[i]\) 表示前 \(i\) 个字符的大于号数量。\(i\) 是一个联通块的右边界,考虑枚举左边界 \(j\) 计算贡献得到转移。

\[dp[i]=
\begin{cases}
s_i =0 & dp[i]=(-1)^{p[i-1]}\sum_{j=0}^{i-1}dp[j]\times (-1)^{p[j]}\dfrac{1}{(i-j)!}
\\ otherwise & dp[i] = 0
\end{cases}
\]

答案的式子就是 \(Ans = n!\times dp[n+1]\) ,

显然可以分治FFT优化转移,复杂度 \(O(n\log^2n)\) 。

code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 1 << 22, mod = 998244353, G = 3;
char s[N];
int js[N], p[N], a[N], b[N], inv[N], dp[N], n;
inline void up(int &x, int y){
x = x + y >= mod ? x + y - mod : x + y;
}
namespace poly{
int rev[N], len, lg;
inline int Pow(int a, int b){
int ans = 1;
for(; b; b >>= 1, a = 1ll * a * a % mod)
if(b & 1) ans = 1ll * ans * a % mod;
return ans;
}
inline void timesinit(int lenth){
for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
for(int i = 0; i < len; i++)
rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1));
}
inline void dft(int *a, int sgn){
for(int i = 0; i < len; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int k = 2; k <= len; k <<= 1){
int w = Pow(G, (mod - 1) / k);
if(sgn == -1) w = Pow(w, mod - 2);
for(int i = 0; i < len; i += k){
int now = 1;
for(int j = i; j < i + (k >> 1); j++){
int x = a[j], y = 1ll * a[j+(k>>1)] * now % mod;
a[j] = x + y >= mod ? x + y - mod : x + y;
a[j+(k>>1)] = x - y < 0 ? x - y + mod : x - y;
now = 1ll * now * w % mod;
}
}
}
if(sgn == -1){
int Inv = Pow(len, mod - 2);
for(int i = 0; i < len; i++) a[i] = 1ll * a[i] * Inv % mod;
}
}
}
using poly::Pow;
inline void solve(int l, int r){
if(l == r){
if(l) dp[l] = p[l-1] & 1 ? mod - dp[l] : dp[l];
if(l != n + 1) dp[l] = p[l] & 1 ? mod - dp[l] : dp[l];
if(l && s[l] == '<') dp[l] = 0;
return;
}
int mid = (l + r) >> 1;
solve(l, mid);
poly::timesinit(2 * (r - l + 1));
for(int i = l; i <= mid; i++) a[i-l] = dp[i];
for(int i = 1; i <= r - l + 1; i++) b[i] = inv[i];
poly::dft(a, 1), poly::dft(b, 1);
for(int i = 0; i < poly::len; i++)
a[i] = 1ll * a[i] * b[i] % mod;
poly::dft(a, -1);
for(int i = mid + 1; i <= r; i++) up(dp[i], a[i-l]);
for(int i = 0; i < poly::len; i++) a[i] = b[i] = 0;
solve(mid + 1, r);
}
int main(){
scanf("%s", s + 1), n = strlen(s + 1);
js[0] = inv[0] = 1;
for(int i = 1; i <= n + 1; i++){
js[i] = 1ll * js[i-1] * i % mod;
inv[i] = Pow(js[i], mod - 2);
}
for(int i = 1; i <= n; i++)
p[i] = p[i-1] + (s[i] == '>');
dp[0] = 1;
solve(0, n + 1);
cout << 1ll * js[n+1] * dp[n+1] % mod;
return 0;
}

「LibreOJ NOI Round #2」不等关系的更多相关文章

  1. LOJ575. 「LibreOJ NOI Round #2」不等关系 [容斥,分治FFT]

    LOJ 思路 发现既有大于又有小于比较难办,使用容斥,把大于改成任意减去小于的. 于是最后的串就长成这样:<<?<?<??<<<?<.我们把一段连续的& ...

  2. LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿

    二次联通门 : LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 /* LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 dp 记录一下前驱 ...

  3. 「LibreOJ NOI Round #1」验题

    麻烦的动态DP写了2天 简化题意:给树,求比给定独立集字典序大k的独立集是哪一个 主要思路: k排名都是类似二分的按位确定过程. 字典序比较本质是LCP下一位,故枚举LCP,看多出来了多少个独立集,然 ...

  4. #509. 「LibreOJ NOI Round #1」动态几何问题

    下面给出部分分做法和满分做法 有一些奇妙的方法可以拿到同样多的分数,本蒟蒻只能介绍几种常见的做法 如果您想拿18分左右,需要了解:质因数分解 如果您想拿30分左右,需要了解:一种较快的筛法 如果您想拿 ...

  5. #510. 「LibreOJ NOI Round #1」动态几何问题

    题目: 题解: 几何部分,先证明一下 \(KX = \sqrt{a},YL = \sqrt{b}\) 设左侧的圆心为 \(O\) ,连接 \(OK\) ,我们有 \(OK = r\). 然后有 \(r ...

  6. #507. 「LibreOJ NOI Round #1」接竹竿 dp

    题目: 题解: 我们考虑把每对花色相同的牌看作区间. 那么如果我们设 \(f_i\) 表示决策在 \([1,i]\) 内的最优答案. 那么有 \(f_i = max\{max\{(f_{j-1}+\s ...

  7. LOJ#510. 「LibreOJ NOI Round #1」北校门外的回忆(线段树)

    题面 传送门 题解 感谢\(@M\_sea\)的代码我总算看懂题解了-- 这个操作的本质就是每次把\(x\)的\(k\)进制最低位乘\(2\)并进位,根据基本同余芝士如果\(k\)是奇数那么最低位永远 ...

  8. LOJ 510: 「LibreOJ NOI Round #1」北校门外的回忆

    题目传送门:LOJ #510. 题意简述: 给出一个在 \(K\) 进制下的树状数组,但是它的实现有问题. 形式化地说,令 \(\mathrm{lowbit}(x)\) 为在 \(K\) 进制下的 \ ...

  9. 「LibreOJ NOI Round #2」单枪匹马

    嘟嘟嘟 这题没卡带一个\(log\)的,那么就很水了. 然后我因为好长时间没写矩阵优化dp,就只敲了一个暴力分--看来复习还是很关键的啊. 这个函数显然是从后往前递推的,那么令第\(i\)位的分子分母 ...

随机推荐

  1. Codevs 2800 送外卖(状压DP)

    2800 送外卖 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n ...

  2. struct tcphdr

    包含在/usr/src/linux/include/linux/tcp.h struct tcphdr { __be16 source; __be16 dest; __be32 seq; __be32 ...

  3. 计蒜客——Reversion Count

    Reversion Count 解析:题目数字的长度最大为 99,因此使用字符串处理,那么必然这些数存在某些规律.对于数 a (XYZW) 和数 b (WZYX),原式 = (1000X + 100Y ...

  4. lintcode-1174.下一个更大的元素 III

    题目描述: 1174. 下一个更大的元素 III 给定一个32位整数n,用同样的数字组成新的32位整数,使得它要比n大,返回最小的这样的数.如果不存在这样的整数,返回-1. 算法思路: 首先将这个数转 ...

  5. [学习笔记] kd-tree

    本文参考这位dalao的题解 前置技能:二叉查找树 其实kd-tree很简单的啦 和BST都差不多的啦 就是在划分的时候把每一维都比较一下就行啦 (\(dalao\)的kd-tree教程) 然而本蒟蒻 ...

  6. TCP的连接如何知道对方已经异常断开

    断电的话,对方不会发送任何数据包过来,包括RST.主机无法得知.如果是TCP已经连接,有个定时器,会发送空包,sequence number不变.如果一直收不到ack,会断定对方已经无法通信,而释放系 ...

  7. 平时常说的ThreadLocal,今天就彻底解决它

    前言 一.了解ThreadLocal的作用 二.ThreadLocal简单使用 三.ThreadLocal原理 3.1 ThreadLocal的存取过程 3.2 探究ThreadLocalMap对象 ...

  8. SQLServer newID()

    一直想找个除了newid() 外高效取随机数的方法, 有点遗憾,木有找到,谁有除了newid()以外更高效的 请留言,谢谢 从A表随机取2条记录,用SELECT TOP 10 * FROM ywle ...

  9. android -------- AES加密解密算法

    AES加密标准又称为高级加密标准Rijndael加密法,是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准.AES的基本要求是,采用对称分组密码体制,密钥长度可以为128.192或25 ...

  10. [Bayes] Concept Search and LDA

    重要的是通过实践更深入地了解贝叶斯思想,先浅浅地了解下LDA. 相关数学知识 LDA-math-MCMC 和 Gibbs Sampling LDA-math - 认识 Beta/Dirichlet 分 ...