题解:考虑没有办法直接dp的原因是每次决策把某个点放入A或者B中不能确定产生了多少贡献。
因此考虑若能将
适当排列,使得
,那么每次某个点
加入A或者B,根据
和
的大小关系,可知产生的贡献为0或者另一部分点集的大小。
那么考虑构造这个排列。考虑若
,那么可以直接把
放到
的右边。否则可以直接将
放到
的右边。递归处理即可。
#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);
}