[题解]P10282 [USACO24OPEN] Smaller Averages G

P10282 [USACO24OPEN] Smaller Averages G

朴素的 DP 比较好写,令 \(f[i][j]\) 为对 \(a[1\sim i],b[1\sim j]\) 进行分段的方案数,则有转移:

\[f[i][j]=\sum_{x,y} f[x][y] \]

其中 \(x\in[0,i-1],y\in[0,j-1],\overline{a[x+1,i]}\le\overline{b[y+1,j]}\)

总时间 \(O(n^4)\),不能接受。

状态数为 \(O(n^2)\) 不好优化,考虑优化转移。

\(i\) 固定的时候,我们可以预处理出 \(a[1\sim i]\) 所有后缀的平均值,并将它们排序;枚举 \(j,q\) 时,可以二分出所有满足条件的 \(p\),前缀和累加即可。总时间 \(O(n^3\log n)\),仍不能接受。

进一步考虑,我们可以只枚举 \(i,q\),并在 \(q\) 固定时,预处理出 \(b[q\sim n]\) 所有前缀的平均值,并将它们排序。在这两个排序的数组上跑双指针 \(p,j\) 即可。总时间 \(O(n^3)\),其中 \(O(n^2\log n)\) 是预处理。

点击查看代码
#include<bits/stdc++.h>
#define eb emplace_back
#define int long long
using namespace std;
const int N=502,P=1e9+7;
int n,a[N],b[N],f[N][N];
struct Nd{double w;int id;};
vector<Nd> x[N],y[N];
inline bool cmp(Nd a,Nd b){return a.w<b.w;}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	for(int i=1;i<=n;i++){
		for(int j=i,s=0;j<=n;j++){
			s+=b[j];
			y[i].eb(Nd{1.0*s/(j-i+1),j});
		}
		for(int j=i,s=0;j;j--){
			s+=a[j];
			x[i].eb(Nd{1.0*s/(i-j+1),j});
		}
		sort(x[i].begin(),x[i].end(),cmp);
		sort(y[i].begin(),y[i].end(),cmp);
	}
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			auto q=x[i].begin();
			int s=0;
			for(Nd p:y[j]){
				for(;q!=x[i].end()&&q->w<=p.w;q++){
					(s+=f[q->id-1][j-1])%=P;
				}
				(f[i][p.id]+=s)%=P;
			}
		}
	}
	cout<<f[n][n]<<"\n";
	return 0;
}
posted @ 2025-11-19 15:54  Sinktank  阅读(123)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.