P8367 [LNOI2022] 盒
又有组合 trick 🥰。
首先这个操作转到前缀和上就是单点加减,最小代价容易得到:
其中 \(S_{a/b}\) 为前缀和。对所有可能的 \(b\) 计数,枚举每一位置上 \(b\) 的前缀和贡献。
组合数即将 \(j\) 分到前 \(i\) 个数,\(S-j\) 分到后 \(n-i\) 个数,容易插板法得出。于是有 \(O(nS)\) 的做法。
绝对值先讨论,钦定 \(j \le S_a(i)\)。
则需要求出:
与
则 \(i\) 位置上的贡献可以表示为:
所以只考虑如何得到 \(f\),\(g\) 可同理维护。
而对于 \(i\) 递增,\(f\) 三、四维也递增,第三维上的增量为 \(O(n)\),第四维的增量为 \(O(S)\)。考虑能否以优秀复杂度实现三、四维上 \(+1\) 的更新。
\(R\gets R+1\) 的更新是容易的,按照上述式子直接计算即可。
于是考虑 \(i\gets i+1\)
对上式有个很牛的组合角度,对于 \(f(n,S,i,R)\) 的组合意义为有 \(S\) 个球,\(n\) 个盒子,其中前 \(i\) 个盒子中球的总数不超过 \(R\) 的方案数。考虑枚举第 \(R+1\) 个球在哪个盒子,得到:
表示前 \(R\) 个球在前 \(j\) 个盒子里任取,后 \(S-R-1\) 个球在 \(j\) 到 \(n\) 的盒子中取。
然后发现 \(i\) 个变化也表示出来了,所以三、四维的 \(+1\) 都能做到 \(O(1)\)。😱
对于 \(j>S_a(i)\) 的部分,以 \(f\) 为例,用全部情况的总贡献即所有球任意分入 \(n\) 个盒子的方案数 \({S+n-1\choose n-1}\) 再去掉 \(j\le S_a(i)\) 的部分即可。
比较坑的是当存在 \(S_a(i)=0\) 时,\(g(n,S,i,R)=i\cdot f(n+1,S-1,i+1,R-1)\) 时 \(R-1\) 会出问题,简单特殊算一下即可。
Takanashi Rikka
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
ll x=0,f=1;char ch=nc();
while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
const int mod=998244353;
#define int ll
ll qp(ll x,int y=mod-2){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=3e6;
int fac[N+5],ifac[N+5];
il int C(int x,int y){return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
struct node{
int n,S,i,R,res;
il node(int x,int y){n=x,S=y,i=R=0,res=C(x+y-1,x-1);}
il void add_i(){(res+=mod-C(R+i,i)*C(S-R+n-i-2,n-i-1)%mod)%=mod,++i;}
il void add_r(){++R,(res+=C(R+i-1,i-1)*C(S-R+n-i-1,n-i-1)%mod)%=mod;}
};
int a[N],w[N];
inline void UesugiErii(){
int n,S=0,ans=0;cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];
for(int i=1;i<n;i++)cin>>w[i];
S=a[n];node x(n,S),y(n+1,S-1);
for(int i=1,tmp=C(S+n-1,n-1),tg=C(S+n-1,n);i<n;i++){
while(x.i<i)x.add_i();
while(x.R<a[i])x.add_r();
if(a[i])
while(y.i<i+1)y.add_i();
while(y.R<a[i]-1)y.add_r();
(ans+=((i*tg%mod+mod-a[i]*tmp%mod)%mod+(a[i]?2*(a[i]*x.res%mod+mod-i%mod*y.res%mod)%mod:0))%mod*w[i]%mod)%=mod;
}
cout<<ans<<'\n';
}
signed main(){
//IO();
cfast;
for(int i=fac[0]=1;i<=N;i++)fac[i]=fac[i-1]*i%mod;
ifac[N]=qp(fac[N],mod-2);
for(int i=N;i;i--)ifac[i-1]=ifac[i]*i%mod;
int _=1;cin>>_;
for(;_;_--)UesugiErii();
return 0;
}

浙公网安备 33010602011771号