suxxsfe

一言(ヒトコト)

LOJ6502「雅礼集训 2018 Day4」Divide

https://loj.ac/p/6502

考虑和 \(w\) 的顺序无关,那么可以把 \(w\) 排成一个更好 dp 的顺序
若将 \(w\) 降序排列,那么对于每个 \(i\) 能使得 \(w_i+w_j\ge m\)\(j\) 是一个前缀,这看起来不错,但 dp 的话需要记录每个这样的前缀 \([1,j]\) 中有几个在 A 集合,仍然不行

但让这个前缀 \([1,j]=[1,i-1]\) 是不现实的,所以可以尝试让 \(j<i\)\(j\) 要么都满足 \(w_i+w_j\ge m\),要么都满足 \(w_i+w_j<m\)
考虑如何构造,若 \(w_1+w_n\ge m\),那么每个 \(1\le j<n\) 都满足 \(w_j+w_n\ge m\),于是 \(w_n\) 置为新排列最后
否则 \(w_1\) 置为新排列最后一样满足预设条件,递归到子问题

所以就可以 \(f_{i,j}\) 表示前 \(i\) 个选了 \(j\) 个在 A 里面的答案了

#define N 2006
int n,m;
int a[N],w[N];
int ge[N];
inline void pre(){
	std::sort(a+1,a+1+n);
	int l=1,r=n;
	while(l<r){
		if(a[l]+a[r]>=m) w[r-l+1]=a[r],ge[r-l+1]=1,r--;
		else w[r-l+1]=a[l],l++;
	}
	w[1]=a[l];
}
#define mod 1000000007
long long max[N][N],f[N][N];
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	pre();
	std::memset(max,188,sizeof max);
	max[1][0]=max[1][1]=0;f[1][0]=f[1][1]=1;
	for(int i=1;i<n;i++){
		for(int j=0;j<=i;j++){
			long long now=max[i][j]+ge[i+1]*(i-j);
			if(max[i+1][j+1]<now) f[i+1][j+1]=0,max[i+1][j+1]=now;
			if(max[i+1][j+1]==now) f[i+1][j+1]=(f[i+1][j+1]+f[i][j])%mod;
			now=max[i][j]+ge[i+1]*j;
			if(max[i+1][j]<now) f[i+1][j]=0,max[i+1][j]=now;
			if(max[i+1][j]==now) f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
		}
	}
	long long ans=0,num=0;
	for(int j=0;j<=n;j++) ans=std::max(ans,max[n][j]);
	for(int j=0;j<=n;j++)if(max[n][j]==ans) num=(num+f[n][j])%mod;
	printf("%lld %lld\n",ans,num);
	return 0;
}
posted @ 2021-10-11 21:35  suxxsfe  阅读(125)  评论(0编辑  收藏  举报