题意:
给定n,k和数组A,重排数组A,最小化 。
题解:
考虑这个东西是隔k个取一个,所以我们把下标按照mod k分类,分成k组
显然每组内部尽量最小化max-min,所以我们考虑给A排序,然后选连续的一段。
显然这k组中有A个size为M,B个size为M+1
所以我们dp[i][x,y]表示选到第i个,x个size为M的,y个size为M+1的
因为k<=5000,所以有效状态数很少
1 #include<bits/stdc++.h> 2 #define pii pair<int,int> 3 #define mp(a,b) make_pair(a,b) 4 #define maxn 300005 5 #define ll long long 6 using namespace std; 7 int n,k; 8 ll a[maxn]; 9 map<pii,ll> dp[maxn]; 10 int main() 11 { 12 scanf("%d%d",&n,&k); 13 for(int i=1;i<=n;++i)scanf("%I64d",&a[i]); 14 sort(a+1,a+n+1); 15 int A=0,B=0,M=0; 16 for(int s=1;s<=k;++s) 17 { 18 int cnt=0; 19 for(int i=s;i<=n;i+=k)++cnt; 20 M=max(M,cnt); 21 } 22 --M; 23 for(int s=1;s<=k;++s) 24 { 25 int cnt=0; 26 for(int i=s;i<=n;i+=k)++cnt; 27 if(cnt==M)++A; 28 if(cnt==M+1)++B; 29 } 30 dp[0][mp(0,0)]=0; 31 map<pii,ll>::iterator it; 32 for(int i=0;i<n;++i) 33 { 34 for(it=dp[i].begin();it!=dp[i].end();++it) 35 { 36 int x=(it->first).first,y=(it->first).second; 37 if(x<A) 38 { 39 if(!dp[i+M].count(mp(x+1,y)))dp[i+M][mp(x+1,y)]=(it->second)+a[i+M]-a[i+1]; 40 else dp[i+M][mp(x+1,y)]=min(dp[i+M][mp(x+1,y)],(it->second)+a[i+M]-a[i+1]); 41 } 42 if(y<B) 43 { 44 if(!dp[i+M+1].count(mp(x,y+1)))dp[i+M+1][mp(x,y+1)]=(it->second)+a[i+M+1]-a[i+1]; 45 else dp[i+M+1][mp(x,y+1)]=min(dp[i+M+1][mp(x,y+1)],(it->second)+a[i+M+1]-a[i+1]); 46 } 47 } 48 } 49 printf("%I64d ",dp[n][mp(A,B)]); 50 return 0; 51 }