P10282

思路

首先想到一个\(n^{4}\)的dp,观察数据范围,发现这应该是一个\(n^{3}\)的算法,考虑如何优化。首先把转移方程写出来\(dp_{i,j}=\sum_{0\le ii\le i-1,0\le jj\le j-1,\overline{a_{ii+1}...a{i}}\le \overline{b_{jj+1}...b{j}}} dp_{ii,jj}\),发现都不太好优化。首先枚举\(i\),\(j\)的两维是不可能被优化的,然后考虑枚举\(jj\),然后找到所有满足条件的\(ii\)的和就可以了。如果我们枚举了jj,就可以得出\(\overline{b_{jj+1}...b{j}}\),此时就是要求满足\(\overline{a_{ii+1}...a{i}}\le \overline{b_{jj+1}...b{j}}\)\(ii\)显然这样可以二分,然后与处理一下即可做到\(n^{3}\log n\)。发现瓶颈在二分上,考虑怎样能把二分去掉。发现如果两个平均数都是单调的,那么我们就可以使用双指针了。

实现

思路大概想好了,首先我们枚举了\(i,j,jj\),然后第三层循环里面是一个双指针。

比如当前的ii(红色),jj(蓝色),做到了这里,那么这个蓝色就可以和箭头指向的红色的前面(包含这个)产生贡献。而这个是可以用前缀和优化的。然后这样我们的实现也清楚了,就是搞出sum[j][i]表示当\(jj=j\)时,前i的a的平均数产生的贡献(可以看代码理解一下)然后就可以了

我也不知道我这个大常数选手怎么没被卡

#include<bits/stdc++.h>
#define for1(i,a,b) for( int i=(a);i<=(b);i++)
#define for2(i,a,b) for( int i=(a);i<(b);i++)
#define for3(i,a,b) for( int i=(a);i>=(b);i--)
#define for4(i,a,b) for( int i=(a);i>(b);i--)
#define mx(a,b) max(a,b)
#define mn(a,b) min(a,b)
#define puba push_back
#define mem(a) memset((a),0,sizeof((a)))
#define int long long
using namespace std;
const int mod=1e9+7;
int n,a[505],b[505],dp[505][505];
int suma[505],sumb[505],sum[505][505];
struct node{
    int l,sum;
}ai[505][505],bi[505][505];
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n;
	for1(i,1,n){
		cin>>a[i];
		suma[i]=suma[i-1]+a[i];
	}for1(i,1,n){
		cin>>b[i];
		sumb[i]=sumb[i-1]+b[i];
	}
    for1(j,1,n){
        for1(i,1,j){
            ai[j][i].sum=(suma[j]-suma[i-1]);
            bi[j][i].sum=(sumb[j]-sumb[i-1]);
            ai[j][i].l=bi[j][i].l=i;
        }
    }
    for1(i,1,n){
        for1(j,1,i){
            for1(k,1,i-1){
                if(ai[i][k].sum*(i-ai[i][k+1].l+1)>ai[i][k+1].sum*(i-ai[i][k].l+1)){
                    swap(ai[i][k],ai[i][k+1]);
                }if(bi[i][k].sum*(i-bi[i][k+1].l+1)>bi[i][k+1].sum*(i-bi[i][k].l+1)){
                    swap(bi[i][k],bi[i][k+1]);
                }
            }//最低级的冒泡排(懒)
        }//还有一个原因是这里为了保证精度需要移项,cmp函数不太好写
    }
	dp[0][0]=1;
	for1(i,1,n){
        for1(j,1,n){
            for1(k,1,i){
                sum[j][k]=(sum[j][k-1]+dp[ai[i][k].l-1][j-1])%mod;
            }//搞出sum
        }
		for1(j,1,n){
			int ii=1;
            for1(jj,1,j){
                while(ai[i][ii].sum*(j-bi[j][jj].l+1)<=bi[j][jj].sum*(i-ai[i][ii].l+1)&&ii<=i) ii++;
                dp[i][j]=(dp[i][j]+sum[bi[j][jj].l][ii-1])%mod;//双指针出的是第一个不满足要求的,所以是ii-1
            }
		}
	}
	cout<<dp[n][n];
	
	return 0;
}
posted @ 2024-04-17 20:30  wuhupai  阅读(5)  评论(0编辑  收藏  举报