题面

有一个长为

N

N

N 的序列,相邻的两个数中只能选一个,总共选

k

k

k 个数,一种方案的价值为选的

k

k

k 个数的和,问所有合法方案的价值总和,答案对 998244353 取模。

1

N

3

1

0

5

,

1

k

N

2

1\leq N\leq 3\cdot10^5~,~1\leq k\leq \left\lceil \frac{N}{2} \right\rceil

1≤N≤3⋅105 , 1≤k≤⌈2N​⌉.

题解

把每个数的贡献拆开求,答案就是 每个数的值 × 该数被选的方案数。这是最基本的转化。

G

(

n

,

i

,

k

)

G(n,i,k)

G(n,i,k) 表示

n

n

n 个数中选

k

k

k 个数,必选第

i

i

i 个数的方案数。

我们先鲁莽地列个式子,枚举第

i

i

i 个数前面选了多少个数,然后就是个放球问题,不难发现

G

(

n

,

i

,

k

)

=

j

=

0

(

i

1

)

/

2

C

i

1

j

j

C

n

i

k

1

+

j

k

1

j

G(n,i,k)=\sum_{j=0}^{(i-1)/2}C_{i-1-j}^{j}\cdot C_{n-i-k-1+j}^{k-1-j}

G(n,i,k)=∑j=0(i−1)/2​Ci−1−jj​⋅Cn−i−k−1+jk−1−j​

——毫无可做性。

我们得换个思路想。不妨容斥一下?先设

f

(

n

,

k

)

f(n,k)

f(n,k) 为在

n

n

n 个数中选

k

k

k 个数的总方案数,可得

f

(

n

,

k

)

=

C

n

k

+

1

k

f(n,k)=C_{n-k+1}^{k}

f(n,k)=Cn−k+1k​。

然后这里利用了官解里所说的 “ 化环 ” 的思想。

如果把整个序列视为一个环(即第一个点和最后一个点不能同时选),那么

G

(

n

,

1

,

k

)

=

G

(

n

,

2

,

k

)

=

=

G

(

n

,

n

,

k

)

G'(n,1,k)=G'(n,2,k)=\cdots=G'(n,n,k)

G′(n,1,k)=G′(n,2,k)=⋯=G′(n,n,k),不妨令此时的

G

(

n

,

1

,

k

)

=

G

(

n

,

2

,

k

)

=

=

G

(

n

,

n

,

k

)

=

F

(

n

,

k

)

G'(n,1,k)=G'(n,2,k)=\cdots=G'(n,n,k)~=~F(n,k)

G′(n,1,k)=G′(n,2,k)=⋯=G′(n,n,k) = F(n,k),则通过一番组合推导,可以发现

F

(

n

,

k

)

=

{

n

<

3

:

[

k

=

=

1

]

n

3

:

f

(

n

3

,

k

1

)

F(n,k)=\bigg\lbrace{\begin{matrix}n<3:~~[k==1]~~~~~~~~~\\ n\geq3:f(n-3,k-1) \end{matrix}}

F(n,k)={n<3:  [k==1]         n≥3:f(n−3,k−1)​

如果不是个环,那就多了一种情况:第一个点和最后一个点同时选,我们把它加上去就行了。选了第一个点和最后一个点后,相当于中间的长度为

n

4

n-4

n−4 的子区间又构成了一个子问题,因此

G

(

n

,

i

,

k

)

G(n,i,k)

G(n,i,k) 有这样的递推公式:

G

(

n

,

i

,

k

)

=

{

i

0

:

0

i

=

1

:

F

(

n

,

k

)

+

f

(

n

4

,

k

2

)

i

>

1

:

F

(

n

,

k

)

+

G

(

n

4

,

i

2

,

k

2

)

i

>

n

2

:

G

(

n

,

n

i

+

1

,

k

)

G(n,i,k)=\begin{cases} i\leq0: & 0\\ i=1: & F(n,k)+f(n-4,k-2)\\ i>1: & F(n,k)+G(n-4,i-2,k-2)\\ i>\lceil\frac{n}{2}\rceil: & G(n,n-i+1,k) \end{cases}

G(n,i,k)=⎩⎪⎪⎪⎨⎪⎪⎪⎧​i≤0:i=1:i>1:i>⌈2n​⌉:​0F(n,k)+f(n−4,k−2)F(n,k)+G(n−4,i−2,k−2)G(n,n−i+1,k)​

我们将一般情况(

i

>

1

i>1

i>1)展开,可以得到:

G

(

n

,

i

,

k

)

=

F

(

n

,

k

)

+

F

(

n

4

,

k

2

)

+

F

(

n

8

,

k

4

)

+

G(n,i,k)=F(n,k)+F(n-4,k-2)+F(n-8,k-4)+\cdots

G(n,i,k)=F(n,k)+F(n−4,k−2)+F(n−8,k−4)+⋯

不难发现对于不同的

i

i

i ,前面部分都是一样的,

i

i

i 只决定式子长度以及最后一项!

那么我们就可以从左到右遍历

i

i

i 的时候把

G

(

n

,

i

,

k

)

G(n,i,k)

G(n,i,k) 衔接着求,只求前一半。每次到新的

i

i

i 最多会增加或减少一两项。由于递推式中每次

i

i

i 会减少 2,且

i

=

1

i=1

i=1 属于特殊情况,所以要分奇偶性讨论。

具体实现有点细节,但是只求前一半,再考虑考虑边界应该就没问题了。

时间复杂度

O

(

n

)

O(n)

O(n)。

CODE

#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
#define INF 0x3f3f3f3f
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
int a[MAXN];
int fac[MAXN],inv[MAXN],invf[MAXN];
inline int qkpow(int a,int b) {
int res = 1;
while(b > 0) {
if(b & 1) res = res *1ll* a % MOD;
a = a *1ll* a % MOD; b >>= 1;
}return res;
}
inline int C(int n,int m) {
if(m < 0 || m > n) return 0;
return 1ll*fac[n] * invf[n-m] % MOD *invf[m] % MOD;
}
inline int f_(int n,int k) {return C(n-k+1,k);}
inline int F(int n,int k) {
if(n <= 3) {
if(k == 1) return 1;
else return 0;
}
else return f_(n-3,k-1);
}
int tm[MAXN];
int main() {
n = read();k = read();int D = read();
int ans = 0;
fac[0] = fac[1] = inv[0] = inv[1] = invf[1] = invf[0] = 1;
for(int i = 2;i <= n;i ++) {
fac[i] = fac[i-1] *1ll* i % MOD;
inv[i] = (MOD-inv[MOD%i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
for(int i = 1;i <= n;i ++) {
a[i] = read(); tm[i] = -1;
}
int ans0 = 0,ans1 = f_(n,k),ad1 = 0,ad2 = 0;
for(int i = 1;i <= n;i ++) {
if(i & 1) {
(ans1 += MOD-f_(n-4*ad1,k-2*ad1)) %= MOD;
(ans1 += F(n-4*ad1,k-2*ad1)) %= MOD;
ad1 ++;
(ans1 += f_(n-4*ad1,k-2*ad1)) %= MOD; if(tm[i] >= 0) ans1 = tm[i];
else tm[i] = tm[n-i+1] = ans1;
(ans += ans1 *1ll* a[i] % MOD) %= MOD;
}
else {
(ans0 += F(n-4*ad2,k-2*ad2)) %= MOD; ad2 ++; if(tm[i] >= 0) ans0 = tm[i];
else tm[i] = tm[n-i+1] = ans0;
(ans += ans0 *1ll* a[i] % MOD) %= MOD;
}
}
printf("%d\n",ans);
return 0;
}

ARC120F Wine Thief (组合数学)的更多相关文章

  1. 17995 Stupid thief 组合数学

    17995 Stupid thief 时间限制:1000MS  内存限制:65535K提交次数:0 通过次数:0 题型: 编程题   语言: 不限定 Description A stupid thie ...

  2. 记录在linux下的wine生活

    记录在linux下的windows生活 本篇内容涉及QQ.微信.Office的安装配置 QQ: 到deepin下载轻聊版. 如果安装了crossover,那么将其中opt/cxoffice/suppo ...

  3. linux Mint wine安装qq,桌面快捷键配置

    在桌面新建qq.desktop文件,添加以下内容 #!/usr/bin/env xdg-open[Desktop Entry]Comment=QQTerminal=falseName=QQExec=w ...

  4. Wine——在Linux上运行Windows软件

    官网:https://www.winehq.org/ 参考: wikipedia 教你使用Wine在Linux上运行Windows软件 如何安装和使用Wine,以便在Linux上运行Windows应用 ...

  5. codeforces 632+ E. Thief in a Shop

    E. Thief in a Shop time limit per test 5 seconds memory limit per test 512 megabytes input standard ...

  6. linux安装wine

    1.添加PPA sudo add-apt-repository ppa:ubuntu-wine/ppa 2.更新列表 sudo apt-get update 3.安装Wine sudo apt-get ...

  7. Codeforces632E Thief in a Shop(NTT + 快速幂)

    题目 Source http://codeforces.com/contest/632/problem/E Description A thief made his way to a shop. As ...

  8. CentOS 安装 Wine

    1. 下载安装包 Wine的中文官网可以下载到最新稳定和开发版本的Wine安装包,根据不同需求可以自行下载 2. 解压安装包,编译前检查 根据不同的平台选择不同的编译选项: For 32-Bit Sy ...

  9. wine

    sudo dpkg --add-architecture i386 sudo add-apt-repository ppa:wine/wine-buildssudo apt-get update su ...

随机推荐

  1. Caller 服务调用 - Dapr

    前言 上一篇我们讲了使用HttpClient的方式调用,那么如果我们现在需要更换为通过dapr实现服务调用,我们需要做哪些事情呢? Caller.Dapr 入门 如果我们的项目原本使用的是Caller ...

  2. .NET6 开源之JSON 2 SQL (JORM框架)

    什么是JORM框架? 全称 :Json  Object Relational Mapping   ,它是通过JSON 对象 去实现数据库的一个关系映射 ,我理想中完整的JORM包含功能有 ·1.表权授 ...

  3. BUUCTF-BJDCTF2020]just_a_rar

    BJDCTF2020]just_a_rar 压缩包提示是四位数密码 爆破得知压缩包密码 16进制查看解压的图片后发现flag flag{Wadf_123}

  4. 从位图到布隆过滤器,C#实现

    前言 本文将以 C# 语言来实现一个简单的布隆过滤器,为简化说明,设计得很简单,仅供学习使用. 感谢@时总百忙之中的指导. 布隆过滤器简介 布隆过滤器(Bloom filter)是一种特殊的 Hash ...

  5. go-zero微服务实战系列(七、请求量这么高该如何优化)

    前两篇文章我们介绍了缓存使用的各种最佳实践,首先介绍了缓存使用的基本姿势,分别是如何利用go-zero自动生成的缓存和逻辑代码中缓存代码如何写,接着讲解了在面对缓存的穿透.击穿.雪崩等常见问题时的解决 ...

  6. RPA视频教程

    匠厂出品,必属精品   Uipath中文社区qq交流群:465630324 uipath中文交流社区:https://uipathbbs.comRPA之家qq群:465620839 第一课--UiPa ...

  7. 学习笔记-JDBC连接数据库操作的步骤

    前言 这里我就以JDBC连接数据库操作查询的步骤作以演示,有不到之处敬请批评指正! 一.jdbc连接简要步骤 1.加载驱动器. 2.创建connection对象. 3.创建Statement对象. 4 ...

  8. 配置SSM公钥及创建远程仓库和在IEDA中集成git操作

    3.将.ssh下的id_rsa.pub公钥copy到gitee工作台中 4.创建个人仓库 5.设置开源许可证:开源是否可以随意转载,开源但是不能商业使用,不能转载,- 限制! 6.克隆到本地! IDE ...

  9. 千位分隔符在web开发中的作用

    有千位分隔符会被认为是数字,否则在移动端会被直接识别成手机号 在开发实战中主流实现方式是添加meta标签 <meta name="format-detection" cont ...

  10. 【USACO 2012 Open】奶牛赛跑_题解

    奶牛赛跑 目录 奶牛赛跑 题目描述 输入格式 输出格式 样例 样例输入#1 样例输出#1 题解 代码 题目描述 约翰有头奶牛,他为这些奶牛准备了一个周长为的环形跑牛场.所有奶牛从起点同时起跑,奶牛在比 ...