codeforces 571B

题意:

给定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 }
View Code
原文地址:https://www.cnblogs.com/uuzlove/p/10464963.html