Shuffle

题目大意

给定一个长度为 \(n\) 的 01 序列 \(a\),你可以进行至多一次以下操作:

  • 选定 \(a\) 的一个连续段,满足连续段内恰好有 \(k\) 个 \(1\),将该连续段任意排列。

问能产生多少种不同的 01 序列。

思路分析

(这题 \(n\) 完全可以开到 \(10^6\) 或是 \(10^7\),因为存在 \(O(n)\) 的做法。)

考虑 DP。

设 \(f_i\) 表示只考虑 \(1\sim i\) 中的字符,能产生多少种不同的 01 序列。

那么可以列出 DP 方程:

\[f_i=\begin{cases}f_{i-1}+{m-1\choose k-1}&s_i=0\\f_{i-1}+{m-1\choose k}&s_i=1\end{cases}
\]

其中,\(m\) 是 \(i\) 往左的极长 \(k\) 个 \(1\) 的连续段的长度。

解释一下:

我们在考虑 \(f_{i-1}\) 时,是把 \(s_i\) 恒定为 \(s_i\) 做的,而在考虑 \(f_i\) 时为了避免算重,我们强制钦定在 \(i\) 的位置放 \(s_i\) 的相反的数,也就是说,若 \(s_i=0\),我们强制这个位置放 \(1\),那么方案数就是 \({m-1\choose k-1}\),在前 \(m-1\) 个位置上放剩下的 \(k-1\) 个数。\(s_i=1\) 类似。

注意初值,当 \(m\) 第一次存在时,\(f_i={m\choose k}\),这是因为 \(f_i\) 前面没有人算它的重。

实现方式有很多种,我使用了二分实现,时间复杂度为 \(O(n\log n)\)。

代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set> using namespace std;
const int N = 1001000, L = 1000000, mod = 998244353;
#define inf 0x3f3f3f3f
#define int long long int n, k, ans;
int fac[N], inv[N], sum[N]; set <int> S; char s[N]; int q_pow(int a, int b){
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
} int C(int n, int m){
if (n < m) return 0;
return fac[n] * inv[n - m] % mod * inv[m] % mod;
} int find(int s, int k){ // 找到从 s 往左的第 k + 1 个 1 的位置的右边
if (sum[s] < k) return inf;
int l = 1, r = s, ans = 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (sum[s] - sum[mid - 1] <= k) r = mid - 1, ans = mid;
else l = mid + 1;
}
return *(--S.lower_bound(ans)) + 1;
} signed main(){
fac[0] = 1;
for (int i = 1; i <= L; i ++) fac[i] = fac[i - 1] * i % mod;
inv[L] = q_pow(fac[L], mod - 2);
for (int i = L; i >= 1; i --) inv[i - 1] = inv[i] * i % mod;
scanf("%lld %lld", &n, &k);
scanf("%s", s + 1);
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + (s[i] == '1');
S.insert(0);
for (int i = 1; i <= n; i ++) if (s[i] == '1') S.insert(i);
int flag = 0;
for (int i = 1; i <= n; i ++) {
if (sum[i] == k && !flag) ans = (ans + C(i, k)) % mod, flag = 1;
else ans = (ans + C(i - find(i, k), k - (s[i] == '0'))) % mod;
}
if (!flag) ans = 1;
cout << ans << '\n';
return 0;
}

Shuffle 题解的更多相关文章

  1. 算法与数据结构基础 - 贪心(Greedy)

    贪心基础 贪心(Greedy)常用于解决最优问题,以期通过某种策略获得一系列局部最优解.从而求得整体最优解. 贪心从局部最优角度考虑,只适用于具备无后效性的问题,即某个状态以前的过程不影响以后的状态. ...

  2. 【LeetCode】随机化算法 random(共6题)

    [384]Shuffle an Array(2019年3月12日) Shuffle a set of numbers without duplicates. 实现一个类,里面有两个 api,struc ...

  3. 1965: [Ahoi2005]SHUFFLE 洗牌

    1965: [Ahoi2005]SHUFFLE 洗牌 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 408  Solved: 240[Submit][St ...

  4. 算法(第四版)C# 习题题解——3.1

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 查找更方便的版本见:https ...

  5. 算法(第四版)C# 习题题解——2.3

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 查找更为方便的版本见:http ...

  6. 算法(第四版)C# 习题题解——2.2

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 查找更为方便的版本见:http ...

  7. 算法(第四版)C# 习题题解——2.1

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 ...

  8. 算法(第四版)C# 习题题解——1.3

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 ...

  9. POJ 3078 - Shuffle'm Up - [模拟题]

    题目链接:http://poj.org/problem?id=3087 Description A common pastime for poker players at a poker table ...

  10. 算法(第四版)C# 习题题解——1.1

    写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 善用 Ctrl + F 查找题 ...

随机推荐

  1. 《Effective C++ 改善程序与设计的55个具体做法》读书笔记

    1 .让自己习惯C++ 条款01 视C++为一个语言联邦 C Object-Oriented C++ Template C++ STL C++高效编程守则视情况而变化,取决于你使用C++的哪一部分. ...

  2. .NET周刊【7月第3期 2023-07-16】

    国内文章 揭秘 .NET 中的 TimerQueue(上) https://www.cnblogs.com/eventhorizon/p/17557821.html TimerQueue 是.NET中 ...

  3. Windows10 下 Neo4j1.5.8 安装教程

    前言 Neo4j 是一个高性能的.NOSQL 图形数据库,它将结构化数据存储在网络上而不是表中.基于磁盘的.具备完全的事务特性的 Java 持久化引擎,这里就不把他和常用关系型数据库做对比了.因为篇幅 ...

  4. Linux 概念:u-boot

    U-Boot介绍 参考:https://baike.baidu.com/item/U-Boot/10377075 参考:https://u-boot.readthedocs.io/en/latest/ ...

  5. 使用guestmount更改qcow2镜像内容

    参考: 使用guestmount更改qcow2镜像内容 guestmount 安装 yum install libguestfs libguestfs-tools -y 使用 guestmount - ...

  6. 《VTK图形图像开发进阶》第1-2章——一个稍微复杂的VTK程序

    VTK概览 数据可视化主要是通过计算机图形学的方法,以图形.图像等形式清晰有效地传递.表达信息,VTK是数据可视化的工具包. VTK全称(Visualization Toolkit),即可视化工具包, ...

  7. chatglm2-6b模型在9n-triton中部署并集成至langchain实践

    一.前言 近期, ChatGLM-6B 的第二代版本ChatGLM2-6B已经正式发布,引入了如下新特性: ①. 基座模型升级,性能更强大,在中文C-Eval榜单中,以51.7分位列第6: ②. 支持 ...

  8. [ABC146F] Sugoroku

    2023-02-27 题目 题目传送门 翻译 翻译 难度&重要性(1~10):5 题目来源 AtCoder 题目算法 贪心 解题思路 对于第 ii 个点,只要到达 \(s_{i+1}\cdot ...

  9. MindSponge分子动力学模拟——计算单点能(2023.08)

    技术背景 在前面的几篇文章中,我们分别介绍了MindSponge的软件架构.MindSponge的安装与使用和如何在MindSponge中定义一个分子系统.那么就像深度学习中的损失函数,或者目标函数, ...

  10. CodeForces 1367E Necklace Assembly

    题意 给定一个字符串\(s\),长度为\(n\),一根项链为一个环,定义一根项链为\(k-beautiful\),则该项链顺时针转\(k\)下后与原项链相等,给出\(k\),请构造一根最长的\(k-b ...