1. 程式人生 > 其它 >Atcoder 124E Pass to Next

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;
}