Two Sided Cards 题解
前言
五一网课的例题,但是网上没有详细的题解(真的连题解都找不到啊),所以来写一篇,就当攒 RP 了。题目可以在这里提交。原题是 TopCoder - 10947,但是有了账号也交不了?
题目简述
有 \(n\) 张卡片,正面和反面分别组成了 \(1 \sim n\) 的排列。现在你需要将这 \(n\) 张卡片排成一排。卡片可以以任何顺序放置,每张卡片可以显示正面或背面,排成的序列不一定是一个排列。两种方案至少存在一个位置的数字不同,则这两种方案被认为是不同的。求排成的不同的序列的方案数,答案对 \(10^9+7\) 取模。
题目分析
套路地,把卡牌当做边,正面连向反面,建图。发现形成了若干个环。环之间互不影响,所以我们只要求得一个环的方案数 \(W_i\) 即可。进而发现设环的长度为 \(L_i\),则 \(W_i\) 只跟 \(L_i\) 有关,即 \(W_i = f(L_i)\)。
考虑计算 \(f(L)\)。发现方案数和重合的数字个数有关,而每个数字要么出现一次,要么出现两次。故枚举有 \(i\) 个数字出现了两次,求出方案数,总方案数即为所有情况之积。从 \(L\) 个位置中选出 \(2i\) 个位置是重复的,方案数是 \(C_L^{2i}\),若 \(i \neq 0\),则还要乘 \(2\),因为将方案取反可以得到新的方案。接下来,不断从剩下可选的位置中选出重复的那 \(2\) 个位置,这 \(2\) 个位置没有区分。剩下的数随随便排列,方案数是 \((L-2i)!\)。这里方案数是 \(\prod \limits _ {j = 1} ^ {i} C _ {L - 2(j-1)} ^ 2\),化简得 \(\cfrac{n!}{2^i \times (L-2i)!}\)。综上:
f(L) = \sum \limits _ {i = 0} ^ {\left \lfloor \cfrac{L}{2} \right \rfloor} C_L^{2i} \times (2 - [i = 0]) \times \cfrac{L!}{2 ^ i}
\]
故总答案:
ans = \Large \prod \limits _ {i = 1} ^ {cnt} C_{n - \sum \limits _ {j = 1} ^ {i - 1} L_j}^{L_i} \times f(L_i)
\]
总体时间复杂度是 \(\Theta(n)\) 的。
代码
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
#include <iostream>
#include <cstdio>
#define debug(a) cerr << "Line: " << __LINE__ << " " << #a << endl
#define print(a) cerr << #a << "=" << (a) << endl
#define file(a) freopen(#a".in", "r", stdin), freopen(#a".out", "w", stdout)
#define main Main(); signed main(){ return ios::sync_with_stdio(0), cin.tie(0), Main(); } signed Main
using namespace std;
const int mod = 1000000007;
const int inv2 = 500000004;
inline int add(int a, int b){
return a + b >= mod ? a + b - mod : a + b;
}
inline int mul(int a, int b){
return 1ll * a * b % mod;
}
const int N = 100010;
int n, a[N], b[N], trans[N], f[N];
int frac[N], Inv[N], finv[N];
bool vis[N];
inline int C(int n, int m){
return mul(frac[n], mul(finv[m], finv[n - m]));
}
inline int calc(int n){
if (f[n]) return f[n];
int res = 0;
for (int i = 0, mu = 1; i <= n / 2; mu = mul(mu, inv2), ++i){
int z = C(n, i << 1);
if (i > 0) z = mul(z, 2);
z = mul(z, mul(frac[n], mu));
res = add(res, z);
}
return f[n] = res;
}
signed main(){
scanf("%d", &n);
for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
for (int i = 0; i < n; ++i) scanf("%d", &b[i]), trans[a[i] - 1] = b[i] - 1;
frac[0] = 1, finv[0] = 1;
for (int i = 1; i <= n; ++i) frac[i] = mul(frac[i - 1], i), Inv[i] = i == 1 ? 1 : mod - mul(mod / i, Inv[mod % i]), finv[i] = mul(finv[i - 1], Inv[i]);
int res = 1;
for (int i = 0, j, l = 0, r = n; i < n; ++i) if (!vis[i]){
for (j = i, l = 0; !vis[j]; ++l, vis[j] = true, j = trans[j]);
res = mul(mul(res, C(r, l)), calc(l)), r -= l;
}
printf("%d\n", res);
return 0;
}
Two Sided Cards 题解的更多相关文章
- CF949E Binary Cards 题解
题面 首先发现:一个数最多会出现1次: 然后深入推出:一个数不会既用它又用它的相反数: 这样就可以依次考虑每一位了: 如果所有的数都不含有这一位,那么就直接把所有的数除以2 如果含有,那么就减去这一位 ...
- CF908A New Year and Counting Cards 题解
Content 有 \(n\) 张卡牌,每张卡牌上只会有大小写字母和 \(0\sim 9\) 的阿拉伯数字.有这样一个描述:"如果卡牌正面写有元音字母(\(\texttt{A,E,I,O,U ...
- CF701A Cards 题解
Content 有一个长度为 \(n\) 的数组 \(a_1,a_2,a_3,...,a_n\),试在其中找到 \(\dfrac{n}{2}\) 对数,使得每个数对的元素的和都相等. 数据范围:\(2 ...
- luogu P1446 [HNOI2008]Cards
题目链接 luogu P1446 [HNOI2008]Cards 题解 题意就是求染色方案->等价类 洗牌方式构成成了一个置换群 然而,染色数限制不能用polay定理直接求解 考虑burnsid ...
- [Codeforces 864A]Fair Game
Description Petya and Vasya decided to play a game. They have n cards (n is an even number). A singl ...
- Codeforces 744C Hongcow Buys a Deck of Cards 状压dp (看题解)
Hongcow Buys a Deck of Cards 啊啊啊, 为什么我连这种垃圾dp都写不出来.. 不是应该10分钟就该秒掉的题吗.. 从dp想到暴力然后gg, 没有想到把省下的红色开成一维. ...
- CF815D Karen and Cards 官方题解翻译
看到这道题,网上没有中文版的官方题解,于是就自己翻译了一遍. 不是机器翻译,是一个字一个字纯手翻译的,如果有错误欢迎指正. 比如我们有一张卡片,三个参数分别是 a1 = 4, b1 = 2, c1 = ...
- 题解 CF546C 【Soldier and Cards】
思路 是一道水题,可以用队列+模拟来写,注意不要拿完队列中的元素! 代码 #include<iostream> #include<cstdio> #include<que ...
- CF254A Cards with Numbers 题解
Content 有 \(2n\) 个数,让你找出两两相等的 \(n\) 对数的编号,或者方案不存在. 数据范围:\(1\leqslant n\leqslant 3\times 10^5,1\leqsl ...
- bzoj 1004 Cards
1004: [HNOI2008]Cards Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有 多少种染色方案,Sun ...
随机推荐
- 【IEEE 出版】 第三届能源与电力系统国际学术会议 (ICEEPS 2024)
[连续2届会后4-5个月EI检索,检索稳定!特邀院士.Fellow 报告!]第三届能源与电力系统国际学术会议 (ICEEPS 2024)以"创造更加柔性.智能的能源电力系统"为主题 ...
- Sealos 5.0 正式发布,云本应该是操作系统
把所有资源抽象成一个整体,一切皆应用,这才是云应该有的样子. 2018 年 8 月 15 日 Sealos 提交了第一行代码. 随后开源社区以每年翻倍的速度高速增长. 2022 年我们正式创业,经历一 ...
- 在Linux驱动中使用timer定时器
在Linux驱动中使用timer定时器 原文(有删改): https://www.cnblogs.com/chen-farsight/p/6226562.html 介绍 内核定时器是内核用来控制在未来 ...
- Linux 中内核与应用程序的交互方式:netlink
netlink介绍 一般来说用户空间和内核空间的通信方式有很多种,而Netlink可以实现双工通信. Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应 ...
- python基础-入门必备知识
1 标识符 标识符是编程时使用的名字,用于给变量.函数.语句块等命名,Python 中标识符由字母.数字.下划线组成,不能以数字开头,区分大小写. 以下划线开头的标识符有特殊含义,单下划线开头的标识符 ...
- QT自定义右键菜单
利用QMenu和QAction可以实现非常实用的右键菜单功能.具体实现思路如下: 1.在xxx.h文件中添加如下头文件 #include <QMenu> #include <QCon ...
- redis 乱码:\xac\xed\x00\x05t\x00\x02
前言 学习 spring-boot 的 redis 相关部分,测试时,发现 使用redisTemplate.opsForValue().set("name","tst&q ...
- NewStarCTF 2023 week1
NewStarCTF 2023 WEEK1|CRYPTO brainfuck http://bf.doleczek.pl/ flag{Oiiaioooooiai#b7c0b1866fe58e12} C ...
- Java常用JDK类库和第三方类库
以下是收集的一些有用的第三方库,Java开发人员可以在其应用程序中使用它们来完成许多有用的任务.为了使用这些库,Java开发人员也应该熟悉这些类库. jdk自带的常用类库 java.lang包 jav ...
- Express手稿