2 条题解

  • 1
    @ 2026-7-6 13:35:34

    O_O怎么是构造题

    原题:LOJ6502

    首先我们容易考虑dpdp,设dpi,jdp_{i,j}表示前ii个里面分jj个到AA队的方案数,然后直接转移。

    但是我们无法计算新增加一头牛会增加多少答案,因为我们并不知道前i1i-1头牛中有多少是>mai>m-a_i的。

    所以考虑构造一个aa的排列使得这个容易计算。

    其实我觉得这里想到构造挺没道理的..

    对于一段已排序的牛al...ra_{l...r},若ar+alma_r+a_l \geq m,则ar+al+1...r1ma_r+a_{l+1...r-1} \geq m,这是一个良好的性质。我们可以让ara_ral...r1a_{l...r-1}的后面。

    而若al+ar<ma_l+a_r<m,则al+al+1...r1<ma_l+a_{l+1...r-1}<m,我们也可以让ala_lal+1...ra_{l+1...r}的后面,这样ala_l在计算时直接不造成贡献,也是良好的性质。

    具体地,我们从l=1,r=nl=1,r=n开始考虑,若al+arma_l+a_r \geq m,则将ara_r放在栈顶,否则将ala_l放在栈顶,最后出栈就是一个具有良好性质的aa的排列。

    dpdp时,分类讨论aia_i时哪一种牛即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int mod=1e9+7;
    int n,m,a[101000];
    int b[101000],btt;
    int f[2020][2020],g[2020][2020];
    signed main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	sort(a+1,a+n+1);
    	int l=1,r=n;
    	for(int i=1;i<=n;i++){
    		if(a[r]+a[l]>=m) b[++btt]=a[r--];
    		else b[++btt]=a[l++];
    	}
    	for(int i=1;i<=n/2;i++){
    		swap(b[i],b[n-i+1]);
    	}
    	f[0][0]=0;
    	g[0][0]=1;
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=i;j++){
    			if(b[i]+b[i-1]>=m){
    				if(j<=i-1) f[i][j]=f[i-1][j]+j;
    				if(j) f[i][j]=max(f[i][j],f[i-1][j-1]+i-j);
    				if(j<=i-1) if(f[i-1][j]+j==f[i][j]) g[i][j]+=g[i-1][j];
    				if(j) if(f[i-1][j-1]+i-j==f[i][j]) g[i][j]+=g[i-1][j-1];
    			}else{
    				if(j<=i-1)f[i][j]=f[i-1][j];
    				if(j) f[i][j]=max(f[i][j],f[i-1][j-1]);
    				if(j<=i-1) if(f[i-1][j]==f[i][j]) g[i][j]+=g[i-1][j];
    				if(j) if(f[i-1][j-1]==f[i][j]) g[i][j]+=g[i-1][j-1]; 
    			}
    			g[i][j]%=mod;
    		}
    	}
    	int ans1=0,ans2=0;
    	for(int i=1;i<=n;i++){
    		if(f[n][i]>ans1) ans1=f[n][i],ans2=0;
    		if(f[n][i]==ans1) ans2+=g[n][i];
    		ans2%=mod;
    	}cout<<ans1<<" "<<ans2;
    	return 0;
    }
    

    信息

    ID
    285
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    (无)
    递交数
    72
    已通过
    4
    上传者