Atcoder 124E Pass to Next

Problem Statement

\(N\) people called Person \(1,2,…,N\) are standing in a circle.

For each \(1≤i≤N−1\), Person \(i\)'s neighbor to the right is Person \(i+1\), and Person \(N\)'s neighbor to the right is Person \(1\).

Person \(i\) initially has \(a_{i}\) balls.

They will do the following procedure just once.

  • Each person chooses some (possibly zero) of the balls they have.
  • Then, each person simultaneously hands the chosen balls to the neighbor to the right.
  • Now, make a sequence of length \(N\), where the \(i\)-th term is the number of balls Person \(i\) has at the moment.

Let \(S\) be the set of all sequences that can result from the procedure. For example, when \(a=(1,1,1)\), we have \(S={(0,1,2),(0,2,1),(1,0,2),(1,1,1),(1,2,0),(2,0,1),(2,1,0)}\)

Compute \(∑_{x∈S}∏^{N}_{i=1}x_i\), modulo 998244353.

Constraints

  • All values in input are integers.
  • \(3≤N≤10^5\)
  • \(0≤a_i≤10^9\)

Input

Input is given from Standard Input in the following format:

N
a1 a2 ⋯⋯ aN

Output

Print \(∑_{x∈S}∏^{N}_{i=1}x_i\), modulo 998244353.


Sample Input 1 Copy

Copy

3
1 1 1
Sample Output 1 Copy

Copy

1
  • We have \(S={(0,1,2),(0,2,1),(1,0,2),(1,1,1),(1,2,0),(2,0,1),(2,1,0)}\)
  • \(∑_{x∈S}∏^{N}_{i=1}x_i\) is 11.

Sample Input 2 Copy

Copy

3
2 1 1
Sample Output 2 Copy

Copy

6

Sample Input 3 Copy

Copy

20
5644 493 8410 8455 7843 9140 3812 2801 3725 6361 2307 1522 1177 844 654 6489 3875 3920 7832 5768
Sample Output 3 Copy

Copy

864609205
  • Be sure to compute it modulo 998244353.

题目翻译

有n个人,环形排列,每个人有\(a_i\)个球,每个人同一事件给下一个传递任意数量自己的球。

\(S\)不相同的最终状态的集合,求\(∑_{x∈S}∏^{N}_{i=1}x_i\)

题目解析

首先是,考虑什么情况下两种不同的传递方案可以得到相同的结果

显然传递序列\(1,1,2,2\)\(2,2,3,3\)的最终状态是等价的

归纳得出:两次传递等价满足传递序列的差分序列相同,则最终状态等价

上面两个传递序列差分序列均为\(-1,0,1,0\)

如何除去等价的传递?如果传递序列,如果最小值大于0,那么一定存在更小的等价传递序列

故可以得出最终方案数:\(\prod_{i=1}^{n}{a_i+1}-\prod_{i=1}^{n}{a_i}\)

但是原题并不是求最终方案数,但是最终方案数的计算可以启发:利用容斥原理排除等价的状态

第二个重点是答案需求的表达式,首先\(∏^{N}_{i=1}x_i\)可以表示为第\(i\)个人各自在自己最后拥有的\(x_i\)球中选一个的方案数

这样原题就转换为了分类讨论第\(i\)个人选的一个球分别是前面的人,还是自己的方案数。可以用动态规划解决

\(f[i][j](j=0/1)\),当\(j=0\)时,\(f[i][0]\)表示第 \(i\)个人从自己原本有的球中选球,前 \(i−1\)个人选球的方案数(不考虑自己)。当\(j=1\)时,\(f[i][1]\)表示第 \(i\)个人从前面的球中选球,前 \(i\)个人选球的方案数(考虑自己的方案数)

之所以区分\(j=0\)\(j=1\)不同来源的表达方式,是为了独立不同来源的球

同时注意:前一个人传多少给下一个人与下一个人传出多少之间没有关系。也就是说,传递都是同时发生的

这里设\(S(n)=\sum_{i=1}^n i=\frac{n(n+1)}{2}\) \(g(n)=\sum_{i=1}^{n}{i^2}={\frac{n(n+1)(2n+1)}{6}}\)

\(f[i][0]->f[i+1][0]\)因为\(f[i][0]\)没有计算第\(i\)个人的方案,故\(f[i+1][0]+=f[i][0]*S(a_i)\)

\(f[i][1]->f[i+1][0]\)因为算上了第\(i\)个人方案,只需算上传球方案\(f[i+1][0]+=f[i][1]*(a_i+1)\)

\(f[i][0]->f[i+1][1]\)因为没有计算第\(i\)个人,故需要计算\(i\)\(i+1\)的方案,假如第\(i\)个人剩\(k\)个球,第\(i+1\)人拿\(a_i-k\)个球,总方案为\(\sum_{k=1}^{a_i}{k*(a_i-k)}=a_i*S(a_i)-g(a_i)\),有\(f[i+1][1]+=f[i][0]*(a_i*S(a_i)-g(a_i))\)

\(f[i][1]->f[i+1][1]\)只要计算第\(i+1\)个人从第\(i\)个人获得球的方案,\(f[i+1][1]+=f[i][1]*S(a_i)\)

上面的转移已经体现了区分\(j=0\)方案不包括\(i\)自己和\(j=1\)方案包括\(i\)的作用,当第\(i\)个人选择自己原有的球,第\(i+1\)人选择\(i\)传递的球,那么显然此时两个人的方案应该一起计算。同时\(i+1\)选择\(i\)传递的球,\(i\)选择\(i-1\)传递的球

由于转移是一个环,\(i=n\)需要转移到\(i=1\)。则需要先钦定第1个人是选自己的球还是选第 n 个人传的球(初值设为1,另一个设为0),然后转移一圈。如果初始化钦定 $f[1][0]=1,f[1][1]=0 $ ,那么最终答案就是\(f[1][0]-1\),反过来是一样的。

最后考虑传球最小值不为0的容斥,在调用一次DP并在模拟传球过程中限制传球数不为0。将之前DP的答案减去约束后得到的即为满足不等价条件的方案数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
int n,a[100005];
int Mod=998244353;
ll f[100005][2],inv2,inv3;
ll qpow(ll x,int k){
    ll res=1;
    while (k){
        if (k&1) res=res*x%Mod;
        x=x*x%Mod;
        k>>=1;
    }
    return res;
}
ll dp(int init,int zero){//init表示dp[1][]的初值,zero表示是否不允许0传递   
    memset(f,0,sizeof(f));
    f[1][0]=init;f[1][1]=init^1;
    for (int i=1;i<=n;i++){
        int to=i%n+1;
        ll s=(a[i]-zero+Mod)%Mod;
        //转移时,剩余值为a[i]不合法,因为剩余a[i]代表转移为0
        ll s1=s*(s+1)%Mod*inv2%Mod;
        f[to][0]=(f[to][0]+f[i][0]*s1%Mod)%Mod;
        f[to][0]=(f[to][0]+f[i][1]*(s+1)%Mod)%Mod;
        if (zero) s++;
        //因为对于f[to][1]的转移,传递值0的情况计数为0不会计入结果
        //to选的球是来自i的球,所以此处表示传递值的a[i]合法
        ll s2=s*(s+1)%Mod*inv2%Mod;
        ll s3=s*(s+1)%Mod*(s*2+1)%Mod*inv2%Mod*inv3%Mod;
        f[to][1]=(f[to][1]+f[i][0]*(s2*s%Mod-s3+Mod)%Mod)%Mod;
        f[to][1]=(f[to][1]+f[i][1]*s2%Mod)%Mod;
    }
    if (init) {
        f[1][0]-=1;
        return (f[1][0]+Mod)%Mod;
    }else {
        f[1][1]-=1;
        return (f[1][1]+Mod)%Mod;
    }
}
int main(){
    cin>>n;
    inv2=qpow(2,Mod-2);inv3=qpow(3,Mod-2);
    for (int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    cout<<((dp(0,0)+dp(1,0))%Mod-(dp(0,1)+dp(1,1))%Mod+Mod)%Mod;
}
posted @ 2021-08-12 20:33  Z-Y-Y-S  阅读(81)  评论(0编辑  收藏  举报