P7322

好神仙!

\(\color{#5bc9}\text{提醒,本文有大量没有推到过程的式子,所以读者可以自己遮住先推一下}\)

Inscription:

有一个长度为 \(k\) 的窗口,在一个长度为 \(n\) 的序列 \(a\) 上滑动,请问滑动窗口中的数的 \(\min\) 共有多少种值。

Solution:

接下来我们考虑之后什么情况才会让答案 \(+1\)。

既然每次向右移动 \(1\) 的长度,那么只有可能删除的数或者新加入的数是最小值答案才有可能 \(+1\)。

对于最左边的数是窗口滑动之前是窗口最小值,进行一波推式子之后(此处省略一万行),可以发现它对答案的贡献有:

\[s1=\sum^{n-k}_{i = 1}C^{k-1}_{n-i} \times (n-k)! \times (k-1)! \times (n-k)
\]

解释一下:

其中从左往右,求和符合是枚举这个最小值的大小,组合数是令窗口中剩余的 \(k−1\) 个数大于最小值的值的个数。

两个阶乘分别是窗口外面的数任意排列和窗口内部除去最小值外任意排列。

最后一个 \(n−k\) 是计算排列中窗口可以在的位置有 \(n−k\) 个。

同理新加入的数的的贡献就为:

\[s2=\sum^{n-k}_{i = 1} C^{k}_{n-i} \times (n-k-1)! \times k! \times (n-k)
\]

但是未免有左右两边都是最小的情况,所以我们要减去。

所以需要减掉的部分为:

\[s3=\sum^{n-k}_{i = 1}C^{k-1}_{n-i} \times (n - k - 1)! \times (k - 1)! \times (n-k) \times (i-1)
\]

\(i−1\) 是最右边小于最左边的个数。

\(\color{violet} \text{注意:最后还需要加上每个排列都缺少的 1 答案,也就是总答案加上 n!}\)。

但是我不甘于 \(O(n-k)\) 的做法(除了预处理),于是就有了下面的事情。

我们来化简 \(s1,s2,s3\)(化简过程略,读者可以自己遮住先推一下)。

\[s1 = \sum^{n-k}_{i=1} \dfrac{n-k}{(n-k-i+1)!} \times (n-k)! \times (n-i)!
\]
\[s2 = \sum^{n-k}_{i=1} \dfrac{1}{(n-k-i)!} \times (n-k)! \times (n-i)!
\]
\[s3 = \sum^{n-k}_{i=1} \dfrac{i-1}{(n-k-i+1)!} \times (n-k)! \times (n-i)!
\]

然后呢,就有一个规律,那就是 \(s1 - s3 = s2\)。

所以答案从 \(s1 + s2 - s3 + n!\) 变成了 \(2 \times s2 + n!\)。

但是,我们还不满足。

\(s2\) 仍然可以化简(读者可以自己遮住先推一下)。

\[s2 = \dfrac{(n+1)!}{k+1} - n!
\]

所以把上面这个式子带入求答案的式子。

所以:

\[\dfrac{2 \times (n+1)!}{k+1} - n!
\]

所以完结撒花!!

最后贴上代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
int qpow(int a,int b)
{
int res = 1;
while(b)
{
if(b & 1)
{
res = res * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,k;
cin >> n >> k;
int fac = 1;
for(int i = 1;i <= n;i++)
{
fac = fac * i % mod;
}
cout << (2 * (fac * (n + 1) % mod) * qpow(k + 1,mod - 2) % mod - fac + mod) % mod;
return 0;
}

随机推荐

  1. 力扣383(java&python)-赎金信(简单)

    题目: 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成. 如果可以,返回 true :否则返回 false . m ...

  2. 编码原则 : DRY, KISS, YAGNI, S.O.L.I.D

    Dont Repeat Yourself. Keep is Simple, Stupid. You Ain't Gonna Need It.  你不需要它 ( 不试图添加你认为以后可能需要的代码,适可 ...

  3. 记 dotnet 8.0.4 修复的 WPF 的触摸模块安全问题

    本文记录 dotnet 8.0.4 版本修复的 WPF 的触摸模块安全问题,此问题影响所有的 .NET 版本,修复方法是更新 SDK 和运行时 宣布安全漏洞地址: https://github.com ...

  4. 2019-7-3-Roslyn-理解-msbuild-的清理过程

    title author date CreateTime categories Roslyn 理解 msbuild 的清理过程 lindexi 2019-07-03 18:21:25 +0800 20 ...

  5. S/4 HANA 中的 Email Template

    电子邮件是非常常见的业务需求. SAP 了解这一点,并在 S/4 HANA(cloud和on premise)中引入了非常有趣的功能--Email Template.它将CDS视图和HTML模板结合了 ...

  6. 快速了解Django:核心概念解析与实践指南

    title: 快速了解Django:核心概念解析与实践指南 date: 2024/5/1 20:31:41 updated: 2024/5/1 20:31:41 categories: 后端开发 ta ...

  7. ORACLE查询表的DML最后时间和操作记录条数

    ORACLE查询表的DML最后时间和操作记录条数 其中user代表当前用户的.dba代表的是有dba可以看到的相关表. select * from all_tab_modifications; sel ...

  8. Dash 2.17版本新特性介绍

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/dash-master 大家好我是费老师,不久前Dash发布了其2.17.0版本,执行下面的命令进行最 ...

  9. vim简明文档

    替换 替换当前行第一个 :s/vivian/sky/ 替换当前行第一个 vivian 为 sky 从当前行替换到最后一行 :%s/vivian/sky/g 替换所有行中 vivian 为 sky 查找 ...

  10. Unity新的MeshData API学习

    在新版本的Unity中提供了MeshDataArray和MeshData等多个API,使Mesh数据操作支持多线程:以更好的支持DOTS. API文档:https://docs.unity3d.com ...