"Problem description"
The new student dormitory is open, consisting of M buildings, numbered 1 to M. At first, the student dormitories were empty, and soon there were n students moving in. Just move in one every day.
Every time a new classmate moves into the dormitory, the building will hold a large party. The party's noise is equal to the number of students in the building. Dorm managers don't like noise, so they will empty a building on a regular basis. The method of emptying is to get all the students of the building to another student dormitory (outside the M-building). However, the administrator can only empty the K-times. The minimum value of the sum of the N-day noise.
"Input Format"
The first row of three integers n,m,k.
Next there are n rows, one integer bi (1<=bi<=m) per line, indicating that a student moved into a bi-building dorm on day one.
"Output Format"
An integer that represents the minimum value of the sum of the N-day noise.
"Input Sample"
5 1 2
1
1
1
1
1
"Output Example"
7
"Sample Interpretation"
Example 1 Explanation: The purge operation is performed after the first day and the third day. This noise is 1,1,2,1,2, so the sum of noise is 7.
"Data Range"
1<=n<=1000000,1<=m<=100,1<=k<=500
Source
http://www.cqoi.net:2012/problem.php?id=2916
The idea of doing the problem (wrong solution): To get this problem, the first thought is dynamic planning, but in the design state function when the state function is related to the first day, set is F (i,j) for the first I day to empty the noise and the minimum value of J, so stuck in the derivation state transfer equation.
Problem-solving ideas (positive solution): according to test instructions, because the need for noise and the minimum value, naturally think of using dynamic programming algorithm, according to the data range hint, if according to the previous idea set the state function will be super memory, so set F (i,j) for the first I building empty J times the noise and the minimum value, analysis of the dormitory, The hostel can be emptied 0 times, can be emptied 1 times, ... Can be emptied up to a maximum of J times, so F (i,j) =min{f (i-1,j-k) | 0<=k<=j}+g[i][k],g[i][k] indicates that the minimum value of the noise and the number of k times is emptied in the dormitory I, the boundary is f (0,j) = 0.
The main problem now is how to calculate g[i][k]. Because in order to make the first dormitory empty k after the noise and the smallest, so the number of students in the building I dormitory will be divided evenly into k+1 (note not k), at this time the noise and is the smallest, in the calculation of noise and time, and do not cycle calculation, it is obvious that this is a arithmetic progression summation problem, First calculate the number of students divided into k+1 after the value of T (that is, the number of people before the dormitory emptied) and the number of students divided into k+1 equal parts after the extra number of TT (the extra person in turn into each of the unprecedented dormitory), then g[i][k]= (1+2+...+t) * (k+1) + (t+1) *tt.
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <
Cstring> using namespace std;
const int maxn=1000005;
Const long Long INF=1000000000010LL;
typedef long Long LL;
int n,m,k;
int b[maxn],a[105]; LL g[105][505]; G[I][K] Indicates the minimum value of the noise and the Min/F (i,j) of the empty K-times in the dormitory of the first I dormitories. F (i,j) =min{f (i-1,j-k) +g[i][k] | 0<=k<=j} boundary: F (0,
j) =0 */LL d[105][505];
int Read_ ()//manual input, save time {char s;
S=getchar ();
while (s< ' 0 ' | | s> ' 9 ') S=getchar ();
int x=0;
while (s>= ' 0 ' && s<= ' 9 ') {x=x*10+s-' 0 ';
S=getchar ();
} return x;
} void Solve () {for (Int. i=0;i<=m;i++) for (int j=0;j<=k;j++) D[i][j]=inf;
for (int j=0;j<=k;j++) d[0][j]=0;
for (int i=1;i<=m;i++) for (int j=0;j<=k;j++) {LL t=inf;
for (int k=0;k<=j;k++) t=min (T,d[i-1][j-k]+g[i][k]);
d[i][j]=t;
} cout<<d[m][k]<< ' \ n ';
} int main () {//freopen ("48.in", "R", stdin);
Freopen ("48.out", "w", stdout); scanf ("%d%d%d",&N,&M,&K);
memset (A,0,sizeof (a));
for (int i=1;i<=n;i++) {b[i]=read_ ();
a[b[i]]++;
} for (int i=1;i<=m;i++) for (int k=0;k<=k;k++)//Calculate group weight g[i][k] {LL sum=0;
LL t=a[i]/(k+1), tt=a[i]% (k+1);
sum= (k+1) * (1+t) *t/2+tt* (t+1);
G[i][k]=sum;
} solve ();
return 0; }