LOJ #6502「雅礼集训 2018 Day4」Divide - 构造 - dp

题解:考虑没有办法直接dp的原因是每次决策把某个点放入A或者B中不能确定产生了多少贡献。
因此考虑若能将 { w n } \{w_n\} 适当排列,使得 i [ 1 , n ] ( j [ 1 , i ) w j + w i m ) ( j [ 1 , i ) w j + w i < m ) \forall i\in[1,n]\Rightarrow\left(\forall j\in[1,i)\rightarrow w_j+w_i\ge m\right)\bigcup\left(\forall j\in[1,i)\rightarrow w_j+w_i< m\right) ,那么每次某个点 x x 加入A或者B,根据 w 1 + w x w_1+w_x m m 的大小关系,可知产生的贡献为0或者另一部分点集的大小。
那么考虑构造这个排列。考虑若 w 1 + w n m w_1+w_n\ge m ,那么可以直接把 w n w_n 放到 w 1 w n 1 w_1\dots w_{n-1} 的右边。否则可以直接将 w 1 w_1 放到 w 2 w n w_2\dots w_n 的右边。递归处理即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=2010;int w[N],a[N],mx[N][N],f[N][N];
int main()
{
	int n=inn(),m=inn(),L=1,R=n;
	rep(i,1,n) w[i]=inn();sort(w+1,w+n+1);
	rep(i,1,n) (w[L]+w[R]>=m?a[i]=w[R--]:a[i]=w[L++]);
	reverse(a+1,a+n+1),mx[0][0]=0,f[0][0]=1;
	rep(i,1,n) rep(j,0,i)
	{
		int A,B,&t=f[i][j];
		if(a[1]+a[i]<m) A=(j>0?mx[i-1][j-1]:-1),B=(j<i?mx[i-1][j]:-1);
		else A=(j>0?mx[i-1][j-1]+i-j:-1),B=(j<i?mx[i-1][j]+j:-1);
		mx[i][j]=max(A,B);
		if(A>B) t=f[i-1][j-1];else if(A<B) t=f[i-1][j];
		else t=f[i-1][j-1]+f[i-1][j],(t>=mod?t-=mod:0);
	}
	int ans=-1,cnt=0;rep(i,0,n) ans=max(ans,mx[n][i]);
	rep(i,0,n) if(mx[n][i]==ans) cnt+=f[n][i],(cnt>=mod?cnt-=mod:0);
	return !printf("%d %d\n",ans,cnt);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/87897437
今日推荐