CF1466H Finding satisfactory solutions
CF1466H Finding satisfactory solutions
这题厉害了!
先考虑已知 \(b\) 如何求合法的 \(a\)。由于是排列,就想和置换环扯上关系。考虑将 \(i\) 与 \(i\) 最喜欢的物品连边,形成内向基环森林,直觉告诉我们这个环一定要直接选,事实也就是如此,否则选择 \(S = circle\) 即可满足不合法条件。这样,每次确定一个环并删去,那么就会形成合法的 \(a\)。
现在变成有 \(a\) 计数 \(b\) 了。把置换环抠出来,令环上点为白边,每个点向比环上点更喜欢的点连黑边,那么合法等价于不存在包含黑边的环。
由于 \(n\) 很小,考虑状压 DP。转移考虑一层层连黑边,每次枚举新加进来的环,容斥一下有
\]
其中 \(w_{S,T}\) 表示由 \(T\) 向 \(S\) 连黑边的方案数,显然可以先算出一个点连向 \(S\) 的方案数然后乘起来。
枚举向 \(S\) 连了多少条边,有
\]
这个可以 \(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的更多相关文章
- 多校联训 DP 专题
[UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...
- sentence patterns
第四部分 推理题 1.世界上每个角落的每个人都有立场,都有背景,都有推理性,能推理出一个人语言的真意,才成就了真正的推理能力: 2.换言之,如果你能通过一个人的说话推理出其身份职业,你的推理能 ...
- Images as x-axis labels
Open-source software is awesome. If I found that a piece of closed-source software was missing a fea ...
- Complexity and Tractability (3.44) - The Traveling Salesman Problem
Copied From:http://csfieldguide.org.nz/en/curriculum-guides/ncea/level-3/complexity-tractability-TSP ...
- 理解Backtracking
Backtracking is an algorithm for finding all solutions by exploring all potential candidates. If the ...
- Cplex: MIP Control Callback
*本文主要记录和分享学习到的知识,算不上原创 *参考文献见链接 之前,我们有简单提到Cplex中的MIP Callback Interface,包括了Informational callback, q ...
- [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 ...
- LOJ Finding LCM(math)
1215 - Finding LCM Time Limit: 2 second(s) Memory Limit: 32 MB LCM is an abbreviation used for Least ...
- Finding LCM (最小公倍数)
Finding LCM Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %lld & %llu [Submit] ...
- 14 Finding a Shared Motif
Problem A common substring of a collection of strings is a substring of every member of the collecti ...
随机推荐
- JS 学习笔记 (七) 面向对象编程OOP
1.前言 创建对象有很多种方法,最常见的是字面量创建和new Object()创建.但是在需要创建多个相同结构的对象时,这两种方法就不太方便了. 如:创建多个学生信息的对象 let tom = { n ...
- 「浙江理工大学ACM入队200题系列」问题 E: 零基础学C/C++78——求奇数的乘积
本题是浙江理工大学ACM入队200题第八套中的E题 我们先来看一下这题的题面. 题面 输入 输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你 ...
- SimpleDateFormat线程安全问题排查
一. 问题现象 运营部门反馈使用小程序配置的拉新现金红包活动二维码,在扫码后跳转至404页面. 二. 原因排查 首先,检查扫码后的跳转链接地址不是对应二维码的实际URL,根据代码逻辑推测,可能是acc ...
- 我服了!SpringBoot升级后这服务我一个星期都没跑起来!(上)
最近由于各方面的原因在准备升级 Spring Cloud 和 Spring Boot,经过一系列前置的调研和分析,决定把Spring Boot 相关版本从 2.1.6 升级到 2.7.5,Spring ...
- laravel 腾讯云短信发送
public function tecentSms(Request $request) { $phone = $request->input("hiphone"); $app ...
- phpword 模板文件导出word到服务器 并浏览器下载
模板文件填充 然后生成新文件 //调用PHPwordrequire_once(ROOTPATH . "inc/vendor/autoload.php"); $phpWord = n ...
- C++两种方法改变输出颜色
方法一: 使用 SetConsoleTextAttribute 需要引入 #include "windows.h" SetConsoleTextAttribute(Ge ...
- vulnhub靶场之EVILBOX: ONE
准备: 攻击机:虚拟机kali.本机win10. 靶机:EVILBOX: ONE,下载地址:https://download.vulnhub.com/evilbox/EvilBox---One.ova ...
- 为什么标准库的模板变量都是inline的
最近在看标准库里的type_traits的时候发现了个有趣的地方,几乎所有在标准库里的变量模板都是inline的! 不仅常见的实现上(libstdc++.libc++.ms stl)都是inline的 ...
- oracle 分析函数——ration_to_report 求占有率(百分比)
oracle 的分析函数有很多,但是这个函数总是会忘记,我想通过这种方式能让自己记起来,不至于下次还要百度. 创表.表数据(平时练手的表): prompt PL/SQL Developer impor ...