ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[ARC127 E] Pass to Next —— 组合意义+DP容斥+环上DP

2021-10-12 01:01:10  阅读:161  来源: 互联网

标签:ARC127 limits int sum 容斥 贡献 一个 DP 个球


题目描述

\(n\) 个人排成一个环,第 \(i\) 人有 \(a_i\) 个球。现在,第 \(i\) 个人选择将自己的 \(h_i\;(h_i\in [0,a_i])\) 个球给右边的人 \(j\) \((j=i\%n+1)\)。设过程结束后,第 \(i\) 人拥有的球数为 \(b_i\)。所有可能的情况下的 \(b\) 构成了集合 \(B\),求 \(\sum_{b\in B}\prod_{i=1}^n b_i\)。

思路

注意到多个相同的 \(b\) 不能算多次,什么情况下 \(h\) 不同的时候 \(b\) 会相同?

对于一个 \(h\),如果对任意 \(i\),\(h_i\ge1\),那么我们将所有 \(h_i\) 都减去 \(1\),每一个人多给出去一个,也多得到一个,\(b\) 是不变的。即 \(h\) 的差分相同的时候 \(b\) 不变。显然 \(h\) 差分不同的时候 \(b\) 一定会变。

也就是说,只有当存在一个 \(i\),\(h_i=0\) 的时候,这样的 \(h\) 才要记入答案。

可以容斥,用总方案减去钦定所有 \(h_i\in [1,a_i]\) 的方案,得到的就是至少有一个人不给球的方案。

接下来我们考虑原式的组合意义:对于每种可能分配,完成后每个人再从自己现在所拥有的球中选出一个的总方案。

于是每个人选球可以分成两种情况:1. 从自己没从给出去的球中选;2. 从上一个人给自己的球中选

分成两种情况后,就可以愉快 dp 了!

约定 \(S(n)=\sum_{i=1}^n i\),\(T(n)=\sum_{i=1}^n i^2\)。

容斥的两个方案用一种 dp,设变量 \(q=0/1\),\(q=0\) 表示无限制,\(q=1\) 表示 \(h_i\ge 1\)。

先不考虑环的限制,设状态 \(f[i][j=0/1]\),表示已经讨论了 \(1\sim i\) 的选球情况,\(j=0\) 表示其中第 \(i\) 个人选择从自己没从给出去的球中选,而 \(j=1\) 表示选择从上一个人给自己的球中选。

每次决策从 \(f[i-1]\) 转移到 \(f[i]\),就是选择一个 \(k=h_{i-1}\in[q,a_{i-1}]\),表示 \(i-1\) 给出了 \(k\) 个,\(i\) 得到了 \(k\) 个。

注意到想要计算一个位置 \(i\) 的贡献,就必须知道自己剩下了多少或自己得到了多少。

即 \(f[i][0]\) 实际上只计算了 \(1\sim i-1\) 的贡献,第 \(i\) 个位置要知道自己给出去多少,下一次转移才能计算贡献。

同理,\(f[i][1]\) 就已经计算了 \(1\sim i\) 的贡献,第 \(i\) 个位置只要知道自己得到了多少,这次转移计算。

具体考虑每一个转移:

  1. \(f[i][0]\leftarrow f[i-1][1]\)
    \(i-1\) 已经算过贡献,\(i\) 还不能算,于是方案就是 \(k\) 的取值个数,即:

\[f[i-1][1]\times (a_{i-1}-q+1) \]

  1. \(f[i][1]\leftarrow f[i-1][1]\)
    \(i\) 需要从得到的 \(k\) 个球里面选一个,由 \(k\in [q,a_{i-1}]\) 知贡献为 \(\sum\limits_{k=q}^{a_{i-1}}k\) ,即:

\[f[i-1][1]\times S(a_{i-1}) \]

  1. \(f[i][0]\leftarrow f[i-1][0]\)
    \(i-1\) 需要从剩下的 \(a_{i-1}-k\) 个球里面选一个,而 \(k'=a_{i-1}-k\in [0,a_{i-1}-q]\) ,则贡献为 \(\sum\limits_{k'=0}^{a_{i-1}-q}k'\) ,即:

\[f[i-1][0]\times S(a_{i-1}-q) \]

  1. \(f[i][1]\leftarrow f[i-1][0]\)
    \(i\) 需要从得到的 \(k\) 个球里面选一个,\(i-1\) 也需要从剩下的 \(a_{i-1}-k\) 个球里面选一个,则贡献为 \(\sum\limits_{k=q}^{a_{i-1}}k(a_{i-1}-k)=a_{i-1}\sum\limits_{k=q}^{a_{i-1}}k-\sum\limits_{k=q}^{a_{i-1}}k^2\) ,注意到 \(k=0\) 时贡献为 \(0\) ,即 \(q\) 的值不影响贡献:

\[f[i-1][0]\times (a_{i-1}S(a_{i-1})-T(a_{i-1})) \]

接着考虑环的情况,由于 \(n\) 向 \(1\) 的转移一开始不能完成,因为不知道 \(f[n]\) 的值,于是先钦定人 \(1\) 的选球方式,钦定完后暂且将人 \(1\) 的对应贡献就定为 \(1\) ,如此设定初值,转移一圈得到 \(f[n]\) 后补上 \(1\) 真正的贡献。 对初始的 \(1\) 两种选球方式分别 dp 的答案累加即可。

形式化地,定义变量 \(p=0/1\),\(p=0\) 即 \(1\) 选择自己剩下的球,\(p=1\) 即选择 \(n\) 给的球,

定义初值 \(f[1][0]=\neg p, f[1][1]=p\),则最后 \(f[1][p]\) 即为所求。

对每个 \(p,q\) 分别计算即可。

代码

点击查看代码

#include<bits/stdc++.h>
#define R register int
#define I inline
#define ll long long
using namespace std;
const int N=1e5+3,P=998244353;
int n,a[N],f[N][2];
I ll S(int n){return (n*(n+1ll)>>1)%P;}
I ll T(int n){return n%3==1?(2*n+1)/3*S(n):n*(n+1ll)/6%P*(2*n+1);}
ll dp(bool p,bool q)
{
	f[1][0]=p^1;f[1][1]=p;
	for(R i=1,j;i<=n;i++)
	{
		j=i==n?1:i+1;
		f[j][0]=((a[i]+1ll-q)*f[i][1]+S(a[i]-q)*f[i][0])%P;
		f[j][1]=(S(a[i])*f[i][1]+(a[i]*S(a[i])-T(a[i]))%P*f[i][0])%P;
	}
	return f[1][p];
}
int main()
{
	scanf("%d",&n);
	for(R i=1;i<=n;i++)scanf("%d",a+i);
	ll ans=dp(0,0)-dp(0,1)+dp(1,0)-dp(1,1);
	ans=(ans%P+P)%P;
	printf("%lld\n",ans);
	return 0;
}

标签:ARC127,limits,int,sum,容斥,贡献,一个,DP,个球
来源: https://www.cnblogs.com/nkxjlym/p/15395925.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有