#include <cstdio> #include <cstdlib> #include <iostream> #include <fstream> #include <sstream> #include <set> #include <map> #include <vector> #include <list> #include <algorithm> #include <cstring> #include <cmath> #include <string> #include <queue> #include <bitset> //UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic #include <cassert> #include <iomanip> //do setprecision #include <ctime> #include <complex> using namespace std; #include "message.h" #define FOR(i,b,e) for(int i=(b);i<(e);++i) #define FORQ(i,b,e) for(int i=(b);i<=(e);++i) #define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i) #define REP(x, n) for(int x = 0; x < (n); ++x) #define ST first #define ND second #define PB push_back #define MP make_pair #define LL long long #define ULL unsigned LL #define LD long double const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342; // change the include here!!! #include "dzialka.h" const int MS = 110; const int MR = 75010; const int DIVW = 100; const int DIVK = 750; //wartosci dla wszystkich wierszy int dp[MS][MR]; LL pref[MR]; struct { int h, p; }stos[MS][MR]; // rozmiary poszczegolnych stosow int sz[MS]; // globalna liczba kolumn int M; LL cleanStack(int w) { LL res = 0; //wyzeruj stos i zliczaj pozostale prostokatne - na ostatnim fragmencie wiersza dopiero to zrob while (sz[w]) { int prevh = sz[w] > 1 ? stos[w][sz[w] - 2].h : 0; res += (stos[w][sz[w] - 1].h - prevh) * pref[M - stos[w][sz[w] - 1].p]; sz[w]--; } return res; } // licz od wiersza bw do ew od kolumny bk do ek // ew i ek - jeden za koncem LL go(int bw, int ew, int bk, int ek) { // liczymy sposoby, podobnie do maksa LL res = 0; // inicjalizacja - mamy gotowe wartosci w dp[0] // standardowy algo: // trzymamy stos par (p,h) - pierwsza kolumna na lewo, wysokosc prostokata // i < j => pi < pj && hi < hj --- taki niezmiennik jest na tym stosie // kazda wysokosc przedluzamy w prawo maksymalnie jak sie da FOR(i, bw, ew) { // pamietaj o skalowaniu wierszy int w = i - bw + 1; FOR(j, bk, ek) { bool usableCell = IsUsableCell(i, j); if (!usableCell) dp[w][j] = 0; else dp[w][j] = 1 + dp[w - 1][j]; } //obsluguj fragment wiersza FOR(j, bk, ek) { int curh = dp[w][j]; //nowa wysokosc int last = -1; //ostatnia kolumna sciagnieta ze stosu - przed wlozeniem kazdej, nowej kolumny //dorzucamy ja na szczyt stosu i przy zdjeciu zliczamy wartosci while (sz[w] && stos[w][sz[w] - 1].h > curh) { //do j-1 kolumny wysokosc stos[size-1].h jest ok int prevh = sz[w] > 1 ? stos[w][sz[w] - 2].h : 0; res += (stos[w][sz[w] - 1].h - max(curh, prevh)) * pref[j - stos[w][sz[w] - 1].p]; //tyle jest prostokatow z wysokoscia [poprzednia,akt_wysokosc_na_stosie] last = stos[w][sz[w] - 1].p; //ostatnia sciagnieta ze stosu kolumna //od kolumny last..j-1 wszystkie maja wysokosc > curh sz[w]--; } // jesli stos nie jest pusty i jest na nim taka sama wysokosc, nie dorzucaj nic na stos if (sz[w] && stos[w][sz[w] - 1].h == curh) continue; // dorzuc wysokosc i wez najbardziej na lewo kolumne, ktora ja realizuje stos[w][sz[w]].h = curh; if (last != -1) //pierwsza kolumna na prawo, t.ze wysokosci last..j >= curh stos[w][sz[w]].p = last; else //nic nie sciagnelismy ze stosu, zaczynamy nowa dzialke w kolumnie j stos[w][sz[w]].p = j; sz[w]++; } // gdy doszedles do konca wiersza, wyczysc stos if (ek == M) res += cleanStack(w); } return res; } int main() { int id = MyNodeId(); int ileI = NumberOfNodes(); // Get number of elements int N = GetFieldHeight();// choose main funtion which we distribute // kolumny M = GetFieldWidth(); FORQ(i, 1, M) pref[i] = pref[i - 1] + i; if (N < ileI) ileI = N; if (id >= ileI) return 0; // przygotuj fazy int dv = DIVW * ileI; int ilePhase = N / dv; if (N%dv) ilePhase++; int ileDone = 0; LL sum = 0; REP(c, ilePhase) { // wylicz ile elementow bede przetwarzal w danej fazie int ileNow = min(N, dv); // wylicz ile elementow mam do zrobienia // inaczej dzielimy dane - kazdy robi tyle samo, chyba ze ma numer < reszta, to robi o 1 wiecej int ile = ileNow / ileI; if (id < ileNow % ileI) ile++; // wyznacz poczatek int beg = ileDone; int add = ileNow / ileI; REP(i, id) { beg += add; // zobacz czy poprzednia instancja musiala robic o 1 wiecej if (i < ileNow % ileI) beg++; } int bw = beg, ew = beg + ile; // nie wysylaj jesli jestes ostatnim kompem w ostatniej fazie bool dontSend = (id == ileI - 1 && c == ilePhase - 1); // niezerowy musi zawsze otrzymywac tablice // 0 musi poczawszy od fazy nr 1 bool receive = id || c; // jedz po kolumnach int ilePhaseK = M / DIVK; if (M % DIVK) ilePhaseK++; REP(k, ilePhaseK) { int bk = k*DIVK; int ek = min(M, bk + DIVK); if (receive) { // musi otrzymac od poprzedniego tablice inicjalizacyjna int prev = (id - 1 + ileI) % ileI; Receive(prev); FOR(i, bk, ek) dp[0][i] = GetInt(prev); } sum += go(bw, ew, bk, ek); if (!dontSend) { int nxt = (id + 1) % ileI; FOR(i, bk, ek) PutInt(nxt, dp[ile][i]); Send(nxt); } } ileDone += ileNow; N -= ileNow; } if (id) { // przeslij wyniki do mastera PutLL(0, sum); Send(0); } if (!id) { // odbierz wyniki od pozostalych REP(i, ileI - 1) { int sender = Receive(-1); sum += GetLL(sender); } printf("%lld\n", sum); } return 0; }
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 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | #include <cstdio> #include <cstdlib> #include <iostream> #include <fstream> #include <sstream> #include <set> #include <map> #include <vector> #include <list> #include <algorithm> #include <cstring> #include <cmath> #include <string> #include <queue> #include <bitset> //UWAGA - w czasie kompilacji musi byc znany rozmiar wektora - nie mozna go zmienic #include <cassert> #include <iomanip> //do setprecision #include <ctime> #include <complex> using namespace std; #include "message.h" #define FOR(i,b,e) for(int i=(b);i<(e);++i) #define FORQ(i,b,e) for(int i=(b);i<=(e);++i) #define FORD(i,b,e) for(int i=(b)-1;i>=(e);--i) #define REP(x, n) for(int x = 0; x < (n); ++x) #define ST first #define ND second #define PB push_back #define MP make_pair #define LL long long #define ULL unsigned LL #define LD long double const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342; // change the include here!!! #include "dzialka.h" const int MS = 110; const int MR = 75010; const int DIVW = 100; const int DIVK = 750; //wartosci dla wszystkich wierszy int dp[MS][MR]; LL pref[MR]; struct { int h, p; }stos[MS][MR]; // rozmiary poszczegolnych stosow int sz[MS]; // globalna liczba kolumn int M; LL cleanStack(int w) { LL res = 0; //wyzeruj stos i zliczaj pozostale prostokatne - na ostatnim fragmencie wiersza dopiero to zrob while (sz[w]) { int prevh = sz[w] > 1 ? stos[w][sz[w] - 2].h : 0; res += (stos[w][sz[w] - 1].h - prevh) * pref[M - stos[w][sz[w] - 1].p]; sz[w]--; } return res; } // licz od wiersza bw do ew od kolumny bk do ek // ew i ek - jeden za koncem LL go(int bw, int ew, int bk, int ek) { // liczymy sposoby, podobnie do maksa LL res = 0; // inicjalizacja - mamy gotowe wartosci w dp[0] // standardowy algo: // trzymamy stos par (p,h) - pierwsza kolumna na lewo, wysokosc prostokata // i < j => pi < pj && hi < hj --- taki niezmiennik jest na tym stosie // kazda wysokosc przedluzamy w prawo maksymalnie jak sie da FOR(i, bw, ew) { // pamietaj o skalowaniu wierszy int w = i - bw + 1; FOR(j, bk, ek) { bool usableCell = IsUsableCell(i, j); if (!usableCell) dp[w][j] = 0; else dp[w][j] = 1 + dp[w - 1][j]; } //obsluguj fragment wiersza FOR(j, bk, ek) { int curh = dp[w][j]; //nowa wysokosc int last = -1; //ostatnia kolumna sciagnieta ze stosu - przed wlozeniem kazdej, nowej kolumny //dorzucamy ja na szczyt stosu i przy zdjeciu zliczamy wartosci while (sz[w] && stos[w][sz[w] - 1].h > curh) { //do j-1 kolumny wysokosc stos[size-1].h jest ok int prevh = sz[w] > 1 ? stos[w][sz[w] - 2].h : 0; res += (stos[w][sz[w] - 1].h - max(curh, prevh)) * pref[j - stos[w][sz[w] - 1].p]; //tyle jest prostokatow z wysokoscia [poprzednia,akt_wysokosc_na_stosie] last = stos[w][sz[w] - 1].p; //ostatnia sciagnieta ze stosu kolumna //od kolumny last..j-1 wszystkie maja wysokosc > curh sz[w]--; } // jesli stos nie jest pusty i jest na nim taka sama wysokosc, nie dorzucaj nic na stos if (sz[w] && stos[w][sz[w] - 1].h == curh) continue; // dorzuc wysokosc i wez najbardziej na lewo kolumne, ktora ja realizuje stos[w][sz[w]].h = curh; if (last != -1) //pierwsza kolumna na prawo, t.ze wysokosci last..j >= curh stos[w][sz[w]].p = last; else //nic nie sciagnelismy ze stosu, zaczynamy nowa dzialke w kolumnie j stos[w][sz[w]].p = j; sz[w]++; } // gdy doszedles do konca wiersza, wyczysc stos if (ek == M) res += cleanStack(w); } return res; } int main() { int id = MyNodeId(); int ileI = NumberOfNodes(); // Get number of elements int N = GetFieldHeight();// choose main funtion which we distribute // kolumny M = GetFieldWidth(); FORQ(i, 1, M) pref[i] = pref[i - 1] + i; if (N < ileI) ileI = N; if (id >= ileI) return 0; // przygotuj fazy int dv = DIVW * ileI; int ilePhase = N / dv; if (N%dv) ilePhase++; int ileDone = 0; LL sum = 0; REP(c, ilePhase) { // wylicz ile elementow bede przetwarzal w danej fazie int ileNow = min(N, dv); // wylicz ile elementow mam do zrobienia // inaczej dzielimy dane - kazdy robi tyle samo, chyba ze ma numer < reszta, to robi o 1 wiecej int ile = ileNow / ileI; if (id < ileNow % ileI) ile++; // wyznacz poczatek int beg = ileDone; int add = ileNow / ileI; REP(i, id) { beg += add; // zobacz czy poprzednia instancja musiala robic o 1 wiecej if (i < ileNow % ileI) beg++; } int bw = beg, ew = beg + ile; // nie wysylaj jesli jestes ostatnim kompem w ostatniej fazie bool dontSend = (id == ileI - 1 && c == ilePhase - 1); // niezerowy musi zawsze otrzymywac tablice // 0 musi poczawszy od fazy nr 1 bool receive = id || c; // jedz po kolumnach int ilePhaseK = M / DIVK; if (M % DIVK) ilePhaseK++; REP(k, ilePhaseK) { int bk = k*DIVK; int ek = min(M, bk + DIVK); if (receive) { // musi otrzymac od poprzedniego tablice inicjalizacyjna int prev = (id - 1 + ileI) % ileI; Receive(prev); FOR(i, bk, ek) dp[0][i] = GetInt(prev); } sum += go(bw, ew, bk, ek); if (!dontSend) { int nxt = (id + 1) % ileI; FOR(i, bk, ek) PutInt(nxt, dp[ile][i]); Send(nxt); } } ileDone += ileNow; N -= ileNow; } if (id) { // przeslij wyniki do mastera PutLL(0, sum); Send(0); } if (!id) { // odbierz wyniki od pozostalych REP(i, ileI - 1) { int sender = Receive(-1); sum += GetLL(sender); } printf("%lld\n", sum); } return 0; } |