LOJ6502「雅禮集訓 2018 Day4」Divide
阿新 • • 發佈:2021-10-11
考慮和 \(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\)
否則 \(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; }