Wine Thief
题解
这是F1的题解,不是F2的题解,F2笔者还没做出来,还是笔者太菜了。。。
我们先定义
F
(
x
,
y
)
F(x,y)
F(x,y)表示从
x
x
x个数中选出
y
y
y个不相邻的数的选法,我们可以得到
F
(
x
,
y
)
=
(
x
−
y
−
1
y
−
2
)
+
2
(
x
−
y
−
1
y
−
1
)
+
(
x
−
y
−
1
y
)
F(x,y)=\binom{x-y-1}{y-2}+2\binom{x-y-1}{y-1}+\binom{x-y-1}{y}
F(x,y)=(y−2x−y−1)+2(y−1x−y−1)+(yx−y−1)
相当于我们假定我们现在有
y
y
y个
1
1
1,
x
−
y
x-y
x−y个
0
0
0,我们要将这些
0
0
0都插入到这
y
y
y个
1
1
1之间,保证每两个
1
1
1之间都有至少一个
0
0
0。
那么我们从剩下的
x
−
y
x-y
x−y个
0
0
0中选出
y
−
1
y-1
y−1个
0
0
0,其中第一个
0
0
0必选,记第一个被选中的
0
0
0为
p
i
p_{i}
pi,然后我们将第
p
i
p_{i}
pi到第
p
i
+
1
−
1
p_{i+1}-1
pi+1−1的
0
0
0都放在第
i
i
i个
1
1
1后面。
这样的方法数是
(
x
−
y
−
1
y
−
2
)
\binom{x-y-1}{y-2}
(y−2x−y−1),可以发现,这样得到的
01
01
01序列是唯一的,也就可以对应回原来
x
x
x个数中选择
y
y
y个不同数的情况。
但由于要考虑两个端点的取舍,所以最后得到的答案就是
(
x
−
y
−
1
y
−
2
)
+
2
(
x
−
y
−
1
y
−
1
)
+
(
x
−
y
−
1
y
)
\binom{x-y-1}{y-2}+2\binom{x-y-1}{y-1}+\binom{x-y-1}{y}
(y−2x−y−1)+2(y−1x−y−1)+(yx−y−1)。
那么对于
a
i
a_{i}
ai,它被偷的情况数为
∑
i
=
0
k
−
1
F
(
x
−
2
,
i
)
F
(
n
−
x
−
1
,
k
−
i
−
1
)
\sum_{i=0}^{k-1}F(x-2,i)F(n-x-1,k-i-1)
∑i=0k−1F(x−2,i)F(n−x−1,k−i−1)。
我们记
G
(
x
,
y
,
z
)
G(x,y,z)
G(x,y,z)表示
∑
i
=
0
z
F
(
x
,
i
)
F
(
y
,
z
−
i
)
\sum_{i=0}^{z}F(x,i)F(y,z-i)
∑i=0zF(x,i)F(y,z−i),相当于从两个长度分别为
x
x
x与
y
y
y的序列中选出
z
z
z个不相邻数的方案数。
容易得到递推式,
G
(
x
,
y
,
z
)
=
F
(
x
+
y
,
z
)
+
G
(
x
−
2
,
y
−
2
,
z
−
2
)
G(x,y,z)=F(x+y,z)+G(x-2,y-2,z-2)
G(x,y,z)=F(x+y,z)+G(x−2,y−2,z−2)
由于
F
(
x
+
y
,
z
)
F(x+y,z)
F(x+y,z)相当于第一个序列的最后一个数与第二个序列的第一个数不能同时被选择的情况数,所以我们只需要加上这两个数被同时选择的情况数,也就是
G
(
x
−
2
,
y
−
2
,
z
−
2
)
G(x-2,y-2,z-2)
G(x−2,y−2,z−2)即可。
但明显这样的计算
G
G
G还是
O
(
n
2
)
O\left(n^2\right)
O(n2)的考虑优化。
由于我们需要知道的
G
G
G满足
x
+
y
=
n
−
3
,
z
=
k
x+y=n-3,z=k
x+y=n−3,z=k,我们可以尝试将这个递归暴力解一下。
定义
p
=
min
(
⌊
min
(
x
,
y
)
−
1
2
⌋
,
⌊
k
2
⌋
)
p=\min\left(\left \lfloor\frac{\min(x,y)-1}{2}\right \rfloor,\left \lfloor\frac{k}{2}\right\rfloor\right)
p=min(⌊2min(x,y)−1⌋,⌊2k⌋),
暴力解一下
G
G
G,可得
G
(
x
,
y
,
z
)
=
∑
i
=
0
p
F
(
n
−
3
−
4
p
,
k
−
2
p
)
+
F
(
max
(
x
,
y
)
−
2
p
−
2
,
k
−
2
p
−
2
)
G(x,y,z)=\sum_{i=0}^{p}F(n-3-4p,k-2p)+F(\max(x,y)-2p-2,k-2p-2)
G(x,y,z)=i=0∑pF(n−3−4p,k−2p)+F(max(x,y)−2p−2,k−2p−2)
前面这个可以先通过前缀和求出来,这样每次
G
G
G就是
O
(
1
)
O\left(1\right)
O(1)。
考虑枚举每个
a
i
a_{i}
ai的被选择方案数,可得答案,
A
n
s
=
∑
i
=
1
n
G
(
i
−
2
,
n
−
i
−
1
)
a
i
Ans=\sum_{i=1}^{n}G(i-2,n-i-1)a_{i}
Ans=i=1∑nG(i−2,n−i−1)ai
时间复杂度为 O ( n ) O\left(n\right) O(n)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 300005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x7f7f7f7f;
const int mo=998244353;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,k,D,fac[MAXN],inv[MAXN],f[MAXN],sum[MAXN],ans;
int C(int x,int y){
if(x<y||x<0||y<0)return 0;
return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;
}
int F(int x,int y){
if(y<1)return !y;if(y==1)return x;
if(y==2)return 1ll*(x-1)*(x-2)/2LL%mo;
if(x==1)return 0;int tmp=C(x-y-1,y-1);
return add(add(C(x-y-1,y-2),C(x-y-1,y)),add(tmp,tmp));
}
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=f[1]=1;
for(int i=2;i<=3e5;i++)
fac[i]=1ll*i*fac[i-1]%mo,
f[i]=1ll*(mo-mo/i)*f[mo%i]%mo,
inv[i]=1ll*f[i]*inv[i-1]%mo;
for(int i=0;i*4<=min(2*k-2,n-3);i++){
sum[i]=F(n-3-4*i,k-1-2*i);
if(i>0)sum[i]=add(sum[i-1],sum[i]);
}
}
int G(int x,int y,int k){
if(k<0)return 0;if(x>y)swap(x,y);if(x<=0)return F(y,k);
int p=min((x-1)/2,k/2);return add(sum[p],G(x-2*(p+1),y-2*(p+1),k-2*(p+1)));
}
signed main(){
read(n);read(k);read(D);init();
for(int i=1,x;i<=n;i++)
read(x),ans=add(ans,1ll*x*G(max(i-2,0),max(n-i-1,0),k-1)%mo);
printf("%d\n",ans);
return 0;
}