Niestety, nie byliśmy w stanie w pełni poprawnie wyświetlić tego pliku, ponieważ nie jest zakodowany w UTF-8. Możesz pobrać ten plik i spróbować otworzyć go samodzielnie.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <stdio.h>

long tab[7001][4], n,k,m, pom1,pom2;
char do_kasacji[7001], stop;
long wskaz_kolor[7001], wybrane[7001], SUMA_MAS;
long long ceny_zb[7001], SUMA_CEN;
long na_teraz[100001],na_pozniej[100001];


int SORT_tab(long pocz,long kon) //Przepisane z Cormena
{
long sx,sxx,sxxx,sq,si,sj,pom;
if(pocz<kon)
    {
     sx = tab[kon][1];
     sxx = tab[kon][2];
     sxxx = tab[kon][3];
     si=pocz-1;
     for(sj=pocz;sj<=kon-1;sj++) 
        {
         if (  (tab[sj][1]<sx)  ||  ( (tab[sj][1]==sx)&&(tab[sj][2]<sxx) )  ||  ( (tab[sj][1]==sx)&&(tab[sj][2]==sxx)&&(tab[sj][3]<sxxx) )  )
            {
             si++;
             pom=tab[si][1]; tab[si][1]=tab[sj][1]; tab[sj][1]=pom;
             pom=tab[si][2]; tab[si][2]=tab[sj][2]; tab[sj][2]=pom;
             pom=tab[si][3]; tab[si][3]=tab[sj][3]; tab[sj][3]=pom;
            }
        }
     pom=tab[si+1][1]; tab[si+1][1]=tab[kon][1]; tab[kon][1]=pom;
     pom=tab[si+1][2]; tab[si+1][2]=tab[kon][2]; tab[kon][2]=pom;
     pom=tab[si+1][3]; tab[si+1][3]=tab[kon][3]; tab[kon][3]=pom;
     
     sq=si+1;
     SORT_tab(pocz,sq-1);
     SORT_tab(sq+1,kon);
    }
return 0;
}



int ZWIEKSZ (int poz)
{
// Poza samym zaktualizowaniem wektora 'wybrane', aktualizuj� te� obie sumy.
// Najpierw odejmuj� z pozycji, kt�r� chc� przesun��.
SUMA_CEN -= tab[wybrane[poz]][3];  SUMA_MAS -= tab[wybrane[poz]][2];

//Teraz przesuwam na tej pozycji, ale s� dwie mo�liwo�ci - albo jest ok, albo musz� "przekr�ci�" licznik.
if ( wybrane[poz]+1 < wskaz_kolor[poz+1] )
	{ // Jest ok, w porz�dku, bez �adnych dziwnych ruch�w
	 wybrane[poz]++;
	 SUMA_CEN += tab[wybrane[poz]][3];  SUMA_MAS += tab[wybrane[poz]][2];
	}
else  //Kolejny przekroczy�by sw�j zakres, wi�c trzeba go wsadzi� na pocz�tek zakresu...
	{ //  ... a nast�pnie zwi�kszy� pozycj� wcze�niej.
	 wybrane[poz] = wskaz_kolor[poz];
	 SUMA_CEN += tab[wybrane[poz]][3];  SUMA_MAS += tab[wybrane[poz]][2];
	 if (poz-1 == 0) stop=1;
	 else ZWIEKSZ(poz-1);
	}
return 0;
}



int main()
{
scanf("%ld",&n);
scanf("%ld",&k);
scanf("%ld",&m);
for (int ii=1; ii<=n; ii++)   scanf("%ld %ld %ld",&tab[ii][1],&tab[ii][2],&tab[ii][3]);


/*// PRZYK�AD 1:
n=8;  k=3;  m=9;
tab[1][1]=2;  tab[1][2]=4;  tab[1][3]=4;        tab[2][1]=1;  tab[2][2]=1;  tab[2][3]=3;
tab[3][1]=3;  tab[3][2]=7;  tab[3][3]=3;        tab[4][1]=2;  tab[4][2]=4;  tab[4][3]=3;
tab[5][1]=1;  tab[5][2]=1;  tab[5][3]=2;        tab[6][1]=3;  tab[6][2]=1;  tab[6][3]=4;
tab[7][1]=1;  tab[7][2]=4;  tab[7][3]=3;        tab[8][1]=3;  tab[8][2]=7;  tab[8][3]=5;
//tab[][1]=;  tab[][2]=;  tab[][3]=;        tab[][1]=;  tab[][2]=;  tab[][3]=;
//*/// KONIEC PRZYK�ADU 1.

SORT_tab(1,n);
// Sortuje po wszystkich trzech, wi�c mo�na przejrze�, czy z jakich� mo�na od razu zrezygnowa� i je po prostu usun��?
// Je�li dwie pierwsze liczby s� takie same, to bior� t� warto��, kt�ra jest najmniejsza na trzeciej pozycji.

for (int ii=1; ii<=n; ii++)   do_kasacji[ii]=0;
for (int ii=2; ii<=n; ii++)   if ((tab[ii-1][2]==tab[ii][2]) && (tab[ii-1][1]==tab[ii][1]))   do_kasacji[ii]=1;


//for (int ii=1; ii<=n; ii++)   printf("%ld %ld %ld\n",tab[ii][1],tab[ii][2],tab[ii][3]);
//printf("Do kasacji: ");
//for (int ii=1; ii<=n; ii++)  printf("%d ",do_kasacji[ii]);
//printf("\n\n");

//Teraz kasuj�. W tej samej tablicy, tylko z dwoma licznikami
pom1=0;pom2=1;
while (pom2<=n)
	{
	 while ((do_kasacji[pom2]==1)&&(pom2<=n)) pom2++;
	 //No i ju� tylko kopiowanie
	 if (pom2<=n)
	 	{
	 	 pom1++;
	 	 if (pom1<pom2)
	 	 	{
	 	 	 tab[pom1][1] = tab[pom2][1];
	 	 	 tab[pom1][2] = tab[pom2][2];
	 	 	 tab[pom1][3] = tab[pom2][3];
	 	 	}
	 	 pom2++;
	 	}
	}
n=pom1;

//for (int ii=1; ii<=n; ii++)   printf("%ld %ld %ld\n",tab[ii][1],tab[ii][2],tab[ii][3]);

// Teraz musz� zrobi� pomocnicz� tabel�, kt�ra b�dzie zawiera� pocz�tki i ko�ce danych kolor�w.
for (int ii=0; ii<=k+1; ii++)   wskaz_kolor[ii]=0;
// Po kolei id� po tab... Je�li jest zmiana koloru, to wpisuj� dany pocz�tek.
wskaz_kolor[tab[1][1]]=1; // Pierwszy element
for (int ii=2; ii<=n; ii++)   if (tab[ii-1][1] != tab[ii][1])   wskaz_kolor[tab[ii][1]]=ii;
wskaz_kolor[k+1]=n+1; // Zamykaj�cy element

//printf("Wskaz kolor: ");
//for (int ii=1; ii<=k+1; ii++)  printf("%ld ",wskaz_kolor[ii]);
//printf("\n");

// Sprawdzam, czy gdzie� jest zero - je�li tak, to mo�na poda� odpowied�
for (int ii=1; ii<=k; ii++)   if (wskaz_kolor[ii]==0)
	{ // Brakuje co najmniej jednego z kolor�w, wi�c nie kupi �adnych �elk�w.
	 printf("0\n");
	 for (int jj=1; jj<m; jj++) printf("-1\n");
	 return 0;
	}

// Teraz sprawdzam wszystkie mo�liwe zbiory "po jednym z ka�dego koloru".
// Musz� liczy� ich (mas� modulo m) oraz (sum� cen - long long)
SUMA_CEN=0;
ceny_zb[0]=0;
for (int ii=1; ii<m; ii++) ceny_zb[ii]=100000000000000000;
// Na pocz�tku "wybrane" s� takie same, jak wska�niki kolor�w:
for (int ii=1; ii<=k; ii++)   { wybrane[ii] = wskaz_kolor[ii];  SUMA_CEN += tab[wybrane[ii]][3];  SUMA_MAS += tab[wybrane[ii]][2]; }
// No i pierwszego mo�na ju� wpisa� do tabeli...
// (SUMA_MAS % m) - reszta z dzielenia
if (ceny_zb[SUMA_MAS % m] > SUMA_CEN)   ceny_zb[SUMA_MAS % m] = SUMA_CEN;


// No i teraz w p�tli musz� rozpatrzy� wszystkie mo�liwe zestawy...
stop=0;
while (!stop)
	{
	 ZWIEKSZ(k);
	 // Tutaj mam ju� now� konfiguracj� z ju� gotowymi SUM�_CEN oraz SUM�_MAS
	 if (stop==0) 
	 	{
	 	 if (ceny_zb[SUMA_MAS % m] > SUMA_CEN)   ceny_zb[SUMA_MAS % m] = SUMA_CEN;
	 	}
	}

// No i tutaj powinienem ju� mie� ca�� list� mo�liwych zbior�w (a raczej tylko najlepszych z nich).

//printf("\nCeny dla kolejnych modulo:\n");
//for (long ii=0; ii<m; ii++)   printf("ceny[%ld] = %lld\n",ii,ceny_zb[ii]);

// Przygotowuj� tablic� z indeksami, do kt�rych mam spr�bowa� doda� kolejne ruchy
for (int ii=0; ii<=100000; ii++)  { na_teraz[ii]=0; na_pozniej[ii]=0; }
for (int ii=1; ii<m; ii++)   if(ceny_zb[ii] < 100000000000000000)  
	{
	 na_pozniej[0]++;
	 na_pozniej[na_pozniej[0]]=ii;
	}

while(na_pozniej[0]>0) //Dop�ki jest cokolwiek do sprawdzania jeszcze
	{
	 // Najpierw przepisuj� z na_p�niej do na_teraz.
	 for (int ii=0; ii<=na_pozniej[0]; ii++)   na_teraz[ii]=na_pozniej[ii];
	 // Wyzerowanie tabeli 'na_pozniej':
	 na_pozniej[0]=0;
	 
	 for (int bazowy=1; bazowy<=na_teraz[0]; bazowy++)
	 	{ // Dla ka�dego bazowego elementu sprawdzamy, czy mo�emy doda� kt�rykolwiek, aby polepszy�
	 	 for (int jakis=1; jakis<m; jakis++)   if (ceny_zb[jakis] < 100000000000000000)
	 	 	{ // Sprawdzamy, czy wsp�lna masa modulo oraz wsp�lna cena jest lepsza
	 	 	 SUMA_CEN = ceny_zb[na_teraz[bazowy]] + ceny_zb[jakis];
	 	 	 SUMA_MAS = na_teraz[bazowy] + jakis;
	 	 	 if (ceny_zb[SUMA_MAS % m] > SUMA_CEN)   ceny_zb[SUMA_MAS % m] = SUMA_CEN;
	 	 	}
	 	}
	}

// I zosta�o wypisanie wyniku :)
//printf("WYNIK:\n\n");


for (int ii=0; ii<m; ii++)   
	{
	 if (ceny_zb[ii] < 100000000000000000)   printf("%lld\n",ceny_zb[ii]);
	 else printf("-1\n");
	}


return 0;
}