T3
題目描述
\(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\) 個位置只要知道自己得到了多少,這次轉移計算。
具體考慮每一個轉移:
- \(f[i][0]\leftarrow f[i-1][1]\)
\(i-1\) 已經算過貢獻,\(i\) 還不能算,於是方案就是 \(k\) 的取值個數,即:
- \(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][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]\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\) 的值不影響貢獻:
接着考慮環的情況,由於 \(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)
{
memset(f,0,sizeof f);
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;
}