CF1466H Finding satisfactory solutions

这题厉害了!

先考虑已知 \(b\) 如何求合法的 \(a\)。由于是排列,就想和置换环扯上关系。考虑将 \(i\) 与 \(i\) 最喜欢的物品连边,形成内向基环森林,直觉告诉我们这个环一定要直接选,事实也就是如此,否则选择 \(S = circle\) 即可满足不合法条件。这样,每次确定一个环并删去,那么就会形成合法的 \(a\)。

现在变成有 \(a\) 计数 \(b\) 了。把置换环抠出来,令环上点为白边,每个点向比环上点更喜欢的点连黑边,那么合法等价于不存在包含黑边的环。

由于 \(n\) 很小,考虑状压 DP。转移考虑一层层连黑边,每次枚举新加进来的环,容斥一下有

\[f_S = \sum_{T} (-1)^{|T| + 1} f_{S - T} w_{S - T, T}
\]

其中 \(w_{S,T}\) 表示由 \(T\) 向 \(S\) 连黑边的方案数,显然可以先算出一个点连向 \(S\) 的方案数然后乘起来。

枚举向 \(S\) 连了多少条边,有

\[w_{S, x} = \sum_{i=1}^{|S|} \binom{|S|}{i} i! (n-i-1)!
\]

这个可以 \(O(n^2)\) 预处理。复杂度瓶颈就在于 DP。观察一下状态数,发现好像比较小,实际上最大为 \(1440\)。假设状态数为 \(S\),随便实现一下可以做到 \(O(nS^2)\),很轻松就能通过。

#include <cstdio>

namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
x = 0; char ch = getchar(); int f = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
}
template<typename T>
inline void write(T x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO; const int N = 110;
const int M = 1500;
int n, a[N], vis[N], cnt[N];
int w[N][N], binom[N][N], fac[N];
int f[M], sz[M], m, subs; const int P = 1e9 + 7; inline void add(int &x, int y) {if((x += y) >= P) x -= P;}
inline void sub(int &x, int y) {if((x -= y) < 0) x += P;} inline void encode(int *num, int &x) {
x = 0;
for(int i = 1; i <= n; ++i)
x = x * (cnt[i] + 1) + num[i];
} inline void decode(int x, int *num) {
for(int i = n; i >= 1; --i)
num[i] = x % (cnt[i] + 1), x /= (cnt[i] + 1);
} void prework() {
encode(cnt, m);
fac[0] = 1;
for(int i = 1; i <= n; ++i)
fac[i] = 1ll * fac[i - 1] * i % P;
for(int i = 0; i <= n; ++i)
binom[i][0] = 1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
add(binom[i][j] = binom[i - 1][j], binom[i - 1][j - 1]);
for(int i = 0; i <= n; ++i) {
w[i][0] = 1;
for(int j = 0; j <= i; ++j)
add(w[i][1], 1ll * binom[i][j] * fac[j] % P * fac[n - j - 1] % P);
for(int j = 2; j <= n; ++j)
w[i][j] = 1ll * w[i][j - 1] * w[i][1] % P;
}
static int s[N];
for(int i = 1; i <= m; ++i) {
decode(i, s);
int cnt = 0;
for(int j = 1; j <= n; ++j)
cnt += s[j] * j;
sz[i] = cnt;
}
} int main() {
read(n);
for(int i = 1; i <= n; ++i)
read(a[i]); for(int i = 1; i <= n; ++i) {
if(vis[i]) continue;
int x = i, siz = 0;
do {
vis[x] = 1, ++siz;
x = a[x];
}while(x != i);
++cnt[siz];
} prework(); static int s[N], t[N];
f[0] = 1;
for(int i = 0; i <= m; ++i) {
decode(i, s);
for(int j = 1; j <= i; ++j) {
decode(j, t);
int flag = 0;
int mul = 1, sum = 0;
for(int k = 1; k <= n; ++k) {
if(t[k] > s[k]) flag = 1;
mul = mul * binom[s[k]][t[k]] % P;
sum += t[k];
}
if(flag) continue;
if(sum & 1) add(f[i], 1ll * mul * f[i - j] % P * w[sz[i] - sz[j]][sz[j]] % P);
else sub(f[i], 1ll * mul * f[i - j] % P * w[sz[i] - sz[j]][sz[j]] % P);
}
}
printf("%d\n",f[m]);
return 0;
}

CF1466H Finding satisfactory solutions的更多相关文章

  1. 多校联训 DP 专题

    [UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...

  2. sentence patterns

    第四部分     推理题 1.世界上每个角落的每个人都有立场,都有背景,都有推理性,能推理出一个人语言的真意,才成就了真正的推理能力: 2.换言之,如果你能通过一个人的说话推理出其身份职业,你的推理能 ...

  3. Images as x-axis labels

    Open-source software is awesome. If I found that a piece of closed-source software was missing a fea ...

  4. Complexity and Tractability (3.44) - The Traveling Salesman Problem

    Copied From:http://csfieldguide.org.nz/en/curriculum-guides/ncea/level-3/complexity-tractability-TSP ...

  5. 理解Backtracking

    Backtracking is an algorithm for finding all solutions by exploring all potential candidates. If the ...

  6. Cplex: MIP Control Callback

    *本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 之前,我们有简单提到Cplex中的MIP Callback Interface,包括了Informational callback, q ...

  7. [C1] Andrew Ng - AI For Everyone

    About this Course AI is not only for engineers. If you want your organization to become better at us ...

  8. LOJ Finding LCM(math)

    1215 - Finding LCM Time Limit: 2 second(s) Memory Limit: 32 MB LCM is an abbreviation used for Least ...

  9. Finding LCM (最小公倍数)

    Finding LCM Time Limit: 2000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu [Submit]   ...

  10. 14 Finding a Shared Motif

    Problem A common substring of a collection of strings is a substring of every member of the collecti ...

随机推荐

  1. vue使用elementUI组件提交表单(带图片)到node后台

    1.方法一(图片与表单分开,请求2次) 1.1 前台代码 // elementUI表单 <el-form ref="form" class="forms" ...

  2. 真正“搞”懂HTTP协议03之时间穿梭

    上一篇我们简单的介绍了一下DoD模型和OSI模型,还着重的讲解了TCP的三次握手和四次挥手,让我们在空间层面,稍稍宏观的了解了HTTP所依赖的底层模型,那么这一篇,我们来追溯一下HTTP的历史,看一看 ...

  3. RocketMQ 在物流行业的应用与运维

    本文作者:丁威 - 中通快递资深架构师,<RocketMQ技术内幕>作者,Apache RocketMQ社区首席布道师,公众号「中间件兴趣圈」维护者. 01 物流行业的业务特点 物流行业有 ...

  4. dp状态设计

    迎接仪式 题目描述 LHX 教主要来 X 市指导 OI 学习工作了.为了迎接教主,在一条道路旁,一群"Orz 教主 er"穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字.一 ...

  5. <四>虚函数 静态绑定 动态绑定

    代码1 class Base { public: Base(int data=10):ma(data){ cout<<"Base()"<<endl; } v ...

  6. 基于 RocketMQ 的 Dubbo-go 通信新范式

    本文作者:郝洪范 ,Dubbo-go Committer,京东资深研发工程师. 一.MQ Request Reply特性介绍 什么是 RPC 通信? 如上图所示,类似于本地调用,A 服务响应调用 B ...

  7. Day34:BigDecimal的使用

    BigDecimal 在基本数据类型中对于浮点数的计算时会出现精度丢失的情况,这个时候我们采用BigDecimal类来解决精度丢失的问题. public class Test{ public stat ...

  8. DenseNet 论文解读

    目录 目录 摘要 网络结构 优点 代码 问题 参考资料 摘要 ResNet 的工作表面,只要建立前面层和后面层之间的"短路连接"(shortcut),就能有助于训练过程中梯度的反向 ...

  9. css处理渲染的图片变形问题:object-fit: cover

    object-fit: cover完美解决!~

  10. css样式实现平行四边形

    强大的css样式实现平行四边形: 啥也不说了,直接上代码 <!DOCTYPE html> <html lang="en"> <head> < ...