1 条题解

  • 0
    @ 2026-5-5 19:03:26

    首先设计一个朴素的 dp。fi,jf_{i,j} 表示 a1ia_{1 \ldots i}b1jb_{1 \ldots j} 同时划分成满足条件的若干段的方案数。一个显然的转移方程是:

    $$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})$$

    其中边界值 f0,0=1f_{0,0}=1。如果直接枚举 p,qp,q 则时间复杂度 O(n4)\mathcal{O}(n^4) 无法接受,考虑进行优化。

    发现直接优化比较困难,我们不妨改变一下枚举的方式,枚举 iiqq,再枚举 ppjj,用 fp,qf_{p,q} 去更新 fi,jf_{i,j},这时候就可以使用双指针优化。具体的:对于 iiqq,可以预处理出所有 api(pi)a_{p \ldots i}(p \leq i) 的平均值和所有 aqj(qj)a_{q \ldots j}(q \leq j) 的平均值,用双指针来维护。

    至于为什么要采用这种枚举方式,是因为这样用 fp,qf_{p,q} 去进行更新时,被枚举的 qq 已经确定,才可以使用前缀和优化。如果采用枚举 i,ji,j 的方式,则转移过来的 fp,qf_{p,q} 两维均不确定,较难维护。同理,枚举 p,jp,j 也是可以的,这里就采用枚举 i,qi,q 的方法。

    这样子,枚举 ii、枚举 qq、枚举 j,pj,p,dp 部分复杂度 O(n3)\mathcal{O}(n^3),预处理 O(n2logn)\mathcal{O}(n^2 \log n),可以接受。

    #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
    上传者