【数学】【CF1091D】 New Year and the Permutation Concatenation
Description
给定一个数 \(n\),将所有 \(1~\sim~n\) 的排列按照字典序放到一个序列中,求有多少长度为 \(n\) 的子序列 \(p_i~p_{i+1}~\dots~p_{i + n - 1}\) 满足 \(\sum_{u = i}^{i + n - 1}~p_u~=~\frac{n~\times~(n - 1)}{2}\) 答案对 \(998244353\) 取模
Input
一行一个整数代表 \(n\)
Output
一行一个整数代表答案对 \(998244353\) 取模的结果
Hint
\(1~\leq~n~\leq~10^6\)
Solution
做法有很多呐……
对于一个合法的序列,显然其中 \(1~\sim~n\) 每个元素都出现了一次。可以使用反证法或按照 \(n\) 进行数学归纳证明
那么对于一个合法的序列 \(q\),一共只有两种情况:
1、它是由一段完整的排列构成的
2、它是由前面一段排列的后 \(k\) 位和后面一段排列的前 \(n - k\) 位拼成的。
情况一显然有 \(n!\) 种,于是我们只考虑情况二的答案
考虑求 next_permutation 的算法:找出原排列中最长的单调降序后缀,记长度为 \(k\),然后在后缀中找最小的大于原排列第 \((n - k - 1)\) 位的值,将这两个位置交换。然后将新的后缀按照升序排序(因为原先是降序的,所以这个操作等价于进行reverse)
考虑两个相邻的排列,在前面排列中选 \(k\) 个,后面选 \(n - k\) 的情况,若这种情况合法,则后面一个排列的前 $n - k $ 位与前面一个排列的前 \(n - k\) 位是相同的,即这一段没有发生交换。所以他的后缀的长度 \(len\) 必须满足 \(len~<~k\)。
我们考虑用总方案数减去不合法的方案数:考虑我们对一个排列固定一个选择的数的个数 \(k\),那么它不合法当且仅当整个后缀是单调降序,前面怎么排无所谓,于是这样的排列共有 \(A_n^{n - k}~=~\frac{n!}{k!}\) 个。这些排列在选后面 \(k\) 个作为选出子序列的前缀时全部是不合法的。考虑我们这样等价于枚举选择前一个排列的 \(k\) 的位置,而总共有 \(n~\times~n!\) 个数字,于是这样的位置一共有 \(n~\times~n!\) 种,即方案有这么多种,减去不合法的方案数即为
\]
以上是官方题解
第二种做法与第一种类似,同样依据上面的结论。不过是直接计算方案数。考虑我们如果选择一个排列的后 \(k\) 个位置,我们设这个排列的后 \(k\) 位是单调递增的,则对前面选择没影响的是后 \((n - k)!\) 次排列,因为这几次排列是将后面 \(k\) 位从升序排列到降序,对前面没有影响。
考虑直接枚举 \(k\),前面怎么选无所谓,方案数 \(A_n^k\),后面共有 \((n - k)!\) 种排列。后面这些排列共有 \((n - k)! - 1\) 对,即这么多贡献。于是直接枚举统计答案即可。
以上参考 @DDOSvoid 神仙的做法
第三种做法直接打表找规律,设 \(f_i\) 为输入为 \(i\) 的答案,则
\]
天知道他们是怎么看出规律的
Code
代码依据官方题解算法写成
#include <cstdio>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 1000010;
const int MOD = 998244353;
int n, ans;
int inv[maxn], fac[maxn], fac_inv[maxn];
void Get_Inv(ci);
int main() {
freopen("1.in", "r", stdin);
qr(n);
Get_Inv(n);
fac[1] = 1;
for (rg int i = 2; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % MOD;
ans = 1ll * n * fac[n] % MOD;
for (rg int i = 1; i < n; ++i) {
ans = (ans - 1ll * fac[n] * fac_inv[i] % MOD) % MOD;
}
qw((ans + MOD) % MOD, '\n', true);
return 0;
}
void Get_Inv(ci x) {
inv[1] = 1;fac_inv[1] = 1;
for (rg int i = 2; i <= x; ++i) fac_inv[i] = 1ll * fac_inv[i - 1] * (inv[i] = (1ll * - (MOD / i) * inv[MOD % i]) % MOD) % MOD;
}
【数学】【CF1091D】 New Year and the Permutation Concatenation的更多相关文章
- [CF1091D]New Year and the Permutation Concatenation
link 题目大意 给$n!$个$n$的排列,按字典序从小到大连成一条序列,例如$3$的情况为:$[1,2,3, 1,3,2, 2,1,3 ,2,3,1 ,3,1,2 ,3,2,1]$,问其中长度为$ ...
- Codeforces 1091D New Year and the Permutation Concatenation 找规律,数学 B
Codeforces 1091D New Year and the Permutation Concatenation https://codeforces.com/contest/1091/prob ...
- codeforces#1090 D. New Year and the Permutation Concatenation(打表找规律)
题意:给出一个n,生成n的所有全排列,将他们按顺序前后拼接在一起组成一个新的序列,问有多少个长度为n的连续的子序列和为(n+1)*n/2 题解:由于只有一个输入,第一感觉就是打表找规律,虽然表打出来了 ...
- Good Bye 2018 D. New Year and the Permutation Concatenation
传送门 https://www.cnblogs.com/violet-acmer/p/10201535.html 题意: 求 n 的所有全排列组成的序列中连续的 n 个数加和为 n*(n+1)/2 的 ...
- Codeforces Good Bye 2018 D (1091D) New Year and the Permutation Concatenation
题意:给n!个n的排列,按字典序从小到大连成一条序列,例如3的情况为:[1,2,3, 1,3,2, 2,1,3 ,2,3,1 ,3,1,2 ,3,2,1],问其中长度为n,且和为sum=n*(n+1) ...
- 【Codeforces 1091D】New Year and the Permutation Concatenation
[链接] 我是链接,点我呀:) [题意] 把1~n的n!种排列依次连接成一个长度为nn!的序列. 让你在这个序列当中找长度为n的连续段,使得连续段中的数字的和为n(n-1)/2 输出符合要求的连续段的 ...
- CF Good Bye 2018
前言:这次比赛爆炸,比赛时各种想多,导致写到\(D\)题时思路已经乱了,肝了\(1\)个多小时都没肝出来,\(B\)题中途因为没开\(long\ long\)又被\(HACK\)了..\(C\)题因为 ...
- Good Bye 2018
Good Bye 2018 2018年最后一场CF,OVER! 弱弱的我只能做出3道A,B,D~~~~ 最后几分钟,感觉找到了C题的规律,结束的那一刻,提交了一发 "Wrong answer ...
- Good Bye 2018 (A~F, H)
目录 Codeforces 1091 A.New Year and the Christmas Ornament B.New Year and the Treasure Geolocation C.N ...
随机推荐
- 利用saltstack一键部署多台zookeeper
以上是saltstack上面sls文件存放zookeeper的路径和文件 以上是入口文件把文件夹做成包 重要安装配置在zoo.sls,以下是该sls的内容 zookeeper: file.manage ...
- dvwa学习笔记之xss
反射型Low 直接输入<script>alert(/xss/)</script>就可以发现弹窗Medium 检查源码 可以看到网站对输入字符进行了过滤,尝试双写绕过,构造< ...
- 【quickhybrid】Android端的项目实现
前言 前文中就有提到,Hybrid模式的核心就是在原生,而本文就以此项目的Android部分为例介绍Android部分的实现. 提示,由于各种各样的原因,本项目中的Android容器确保核心交互以及部 ...
- 第一讲:SQL语言概述
SQL语言是集DDL.DML和DCL于一体的数据库语言. SQL语言之DDL:定义数据库 SQL语言之DML:操纵数据库 一.功能概述 SQL语言主要由以下9个单词引导的操作语句来构成,但每一条语句都 ...
- 20172319 《Java程序设计教程》 第10周学习总结
20172319 2018.05.09-05.21 <Java程序设计教程>第10周学习总结 目录 教材学习内容总结 教材学习中的问题和解决过程 代码调试中的问题和解决过程 代码托管 上周 ...
- 第五次作业+4505B寝室队
1.需求分析: 作一个简单的MP3播放器,并能显示播放文件的路径. 2.设计思路: 用窗体设计播放器的界面,以市面上主流的播放器为标准,采用一个窗体的界面. 3.实现的功能: 第一是能播放MP3文件, ...
- keil c51笔记
第一章 Keil C51开发系统基本知识 第一节 系统概述 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上.结构性.可读性. ...
- tomcat文件中server.xml 实例说明
<?xml version='1.0' encoding='utf-8'?> # 这是server类, 指定一个tomcat的应用实例 <Server port="80 ...
- [转帖]真TM长的:SQL Server 2008存储结构——GAM和SGAM、PFS结构、IAM结构、DCM&BCM
谈到GAM和SGAM,我们不得不从数据库的页和区说起. https://blog.csdn.net/snowfoxmonitor/article/details/49991015 一个数据库由用户定义 ...
- Python2X和Python3X的区别
python2X:源码重复不规范python3X:整合源码,更清晰简单优美. python2X:默认的编码是ascii (解决办法为第一行添加 : #-*- encoding:ut ...