题解 P10141 [USACO24JAN] Merging Cells P
Lonely_NewYear · · 题解
P10141 题解
题目大意
有
题目分析
对于每个细胞单独考虑,设当前考虑的细胞为
上面的做法转移的顺序是合并从小区间到大区间的顺序,正难即反,可以发现如果枚举最后一次合并,则最后留下的细胞必定来自总和较大的区间。也就是说,倒着做把合并变成分裂,每次会确定最后留下的细胞来自左侧的区间还是右侧,并将另一部分舍去不必再考虑。设
继续优化,考虑所有能转移到
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5010,mod=1e9+7;
int inv(int a){
int b=mod-2,r=1;
while(b){
if(b&1)r=1ll*r*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return r;
}
void add(int &i,int j){
i=(i+j>=mod?i+j-mod:i+j);
}
int n;
int s[MAXN],v[MAXN];
int d[MAXN][MAXN],f[MAXN][MAXN],g[MAXN][MAXN],p[MAXN],q[MAXN];
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>s[i];
s[i]+=s[i-1];
v[i]=inv(i);
}
d[1][n]=f[1][n]=g[1][n]=v[n-1];
for(int i=1;i<=n;i++)p[i]=n,q[i]=1;
for(int h=n-1;h>=1;h--){
for(int i=1,j=h;j<=n;i++,j++){
while(s[j]-s[i-1]<=s[p[i]]-s[j])p[i]--;
add(d[i][j],f[i][j+1]);
add(d[i][j],mod-f[i][p[i]+1]);
while(s[j]-s[i-1]<s[i-1]-s[q[i]-1])q[i]++;
add(d[i][j],g[i-1][j]);
add(d[i][j],mod-g[q[i]-1][j]);
if(h>1){
d[i][j]=1ll*d[i][j]*v[j-i]%mod;
f[i][j]=f[i][j+1];
add(f[i][j],d[i][j]);
g[i][j]=g[i-1][j];
add(g[i][j],d[i][j]);
}
}
}
for(int i=1;i<=n;i++)cout<<d[i][i]<<'\n';
return 0;
}
谢谢观看!