1 条题解
-
0
首先设计一个朴素的 dp。 表示 和 同时划分成满足条件的若干段的方案数。一个显然的转移方程是:
$$f_{i,j}=\sum_{p,q}f_{p-1,q-1} (\text{average of }a_{p \ldots i} \leq \text{average of }b_{q \ldots j})$$其中边界值 。如果直接枚举 则时间复杂度 无法接受,考虑进行优化。
发现直接优化比较困难,我们不妨改变一下枚举的方式,枚举 和 ,再枚举 和 ,用 去更新 ,这时候就可以使用双指针优化。具体的:对于 和 ,可以预处理出所有 的平均值和所有 的平均值,用双指针来维护。
至于为什么要采用这种枚举方式,是因为这样用 去进行更新时,被枚举的 已经确定,才可以使用前缀和优化。如果采用枚举 的方式,则转移过来的 两维均不确定,较难维护。同理,枚举 也是可以的,这里就采用枚举 的方法。
这样子,枚举 、枚举 、枚举 ,dp 部分复杂度 ,预处理 ,可以接受。
#include <bits/stdc++.h> using namespace std; typedef double db; typedef pair<db,int> pdi; const int N=505,mod=1e9+7; int n,a[N],b[N]; vector<pdi> ave[N]; int f[N][N]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) { int sum=0; for(int j=i;j<=n;j++) { sum+=b[j]; ave[i].emplace_back(make_pair((db)sum/(j-i+1),j)); } sort(ave[i].begin(),ave[i].end()); } f[0][0]=1LL; for(int i=1;i<=n;i++) { int sum=0; vector<pdi> res; for(int j=i;j>=1;j--) { sum+=a[j]; res.emplace_back(make_pair((db)sum/(i-j+1),j)); } sort(res.begin(),res.end()); for(int j=1;j<=n;j++) { auto p=res.begin(); int tmp=0; for(auto [val,q]:ave[j]) { while(p!=res.end()&&(p->first)<=val) tmp=(tmp+f[(p->second)-1][j-1])%mod,p++; f[i][q]=(f[i][q]+tmp)%mod; } } } printf("%lld\n",f[n][n]); return 0; }
- 1
信息
- ID
- 7609
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 14
- 已通过
- 7
- 上传者