[ARC120F]Wine Thief

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)=(y2xy1)+2(y1xy1)+(yxy1)
相当于我们假定我们现在有 y y y 1 1 1 x − y x-y xy 0 0 0,我们要将这些 0 0 0都插入到这 y y y 1 1 1之间,保证每两个 1 1 1之间都有至少一个 0 0 0
那么我们从剩下的 x − y x-y xy 0 0 0中选出 y − 1 y-1 y1 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+11 0 0 0都放在第 i i i 1 1 1后面。
这样的方法数是 ( x − y − 1 y − 2 ) \binom{x-y-1}{y-2} (y2xy1),可以发现,这样得到的 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} (y2xy1)+2(y1xy1)+(yxy1)

那么对于 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=0k1F(x2,i)F(nx1,ki1)
我们记 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,zi),相当于从两个长度分别为 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(x2,y2,z2)
由于 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(x2,y2,z2)即可。

但明显这样的计算 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=n3,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=0pF(n34p,k2p)+F(max(x,y)2p2,k2p2)
前面这个可以先通过前缀和求出来,这样每次 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=1nG(i2,ni1)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;
}

谢谢!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值