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.
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 1048576;
const int DM = 2097152;
int n, N, a, b, poprzednik, g;
int C[2100000];
int D[2100000];
int W[2100000];
int liczba[1000005];
int sposoby[1000005];
int nieujemne[1000005];
int wynik[1000005];
int s;
const int INF = 1000000001;
// MaxTree z "Algorytmiki praktycznej" Piotra Sta�czyka
void Set(int p,int v) {
for(p+=s, W[p]=v, p>>=1; p>0; p>>=1)
W[p] = max(W[p<<1], W[(p<<1)+1]);
}
int Find1(int p, int k) {
int m = -INF;
p+=s; k+=s;
while(p<k) {
if((p&1)==1) m=max(m,C[p++]);
if((k&1)==0) m=max(m,C[k--]);
p>>=1; k>>=1;
}
if(p==k) m=max(m,C[p]);
return m;
}
int Find2(int p, int k) {
int m = INF;
p+=s; k+=s;
while(p<k) {
if((p&1)==1) m=min(m,D[p++]);
if((k&1)==0) m=min(m,D[k--]);
p>>=1; k>>=1;
}
if(p==k) m=min(m,D[p]);
return m;
}
// MaxTree z "Algorytmiki praktycznej" Piotra Sta�czyka
int main ()
{
s = M;
scanf("%d",&n);
N = n + M;
for (int i = M; i < N; ++i) scanf("%d%d",&C[i],&D[i]);
for (int i = M - 1; i > 0; --i) C[i] = max(C[i << 1], C[(i << 1) | 1]);
for (int i = N; i < DM; ++i) D[i] = INF;
for (int i = M - 1; i > 0; --i) D[i] = min(D[i << 1], D[(i << 1) | 1]);
for (int i = 1; i < DM; ++i) W[i] = -1;
sposoby[n] = 1;
nieujemne[n] = n;
Set(n, 0);
for (int i = 0; i < n; ++i) liczba[i] = -1;
for (int i = n - 1; i >= 0; --i)
{
a = 0;
b = n;
poprzednik = i;
for (int j = i + 1; j <= n; )
{
j = nieujemne[j];
if (liczba[i] > wynik[j] + 1) break;
int g = j + s;
while (W[g] < liczba[i] - 1)
{
if (g & 1) g++;
else (g >>= 1);
}
while (g < s)
{
g <<= 1;
if (W[g] < liczba[i] - 1) g |= 1;
}
j = g - s;
a = max(a, Find1(poprzednik, j - 1));
b = min(b, Find2(poprzednik, j - 1));
poprzednik = j;
if (a > b) break;
if (b < j - i) break;
if (j - i < a)
{
j = a + i;
continue;
}
if (liczba[j] >= liczba[i])
{
liczba[i] = liczba[j] + 1;
sposoby[i] = sposoby[j];
}
else
{
sposoby[i] += sposoby[j];
if (sposoby[i] >= 1000000007) sposoby[i] -= 1000000007;
}
j++;
}
if (liczba[i] == -1) nieujemne[i] = nieujemne[i + 1];
else nieujemne[i] = i;
if (liczba[i] > wynik[i + 1]) wynik[i] = liczba[i];
else wynik[i] = wynik[i + 1];
if (liczba[i] != -1) Set(i, liczba[i]);
}
if (liczba[0] == -1) printf("NIE\n");
else printf("%d %d\n", liczba[0], sposoby[0]);
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 | #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int M = 1048576; const int DM = 2097152; int n, N, a, b, poprzednik, g; int C[2100000]; int D[2100000]; int W[2100000]; int liczba[1000005]; int sposoby[1000005]; int nieujemne[1000005]; int wynik[1000005]; int s; const int INF = 1000000001; // MaxTree z "Algorytmiki praktycznej" Piotra Sta�czyka void Set(int p,int v) { for(p+=s, W[p]=v, p>>=1; p>0; p>>=1) W[p] = max(W[p<<1], W[(p<<1)+1]); } int Find1(int p, int k) { int m = -INF; p+=s; k+=s; while(p<k) { if((p&1)==1) m=max(m,C[p++]); if((k&1)==0) m=max(m,C[k--]); p>>=1; k>>=1; } if(p==k) m=max(m,C[p]); return m; } int Find2(int p, int k) { int m = INF; p+=s; k+=s; while(p<k) { if((p&1)==1) m=min(m,D[p++]); if((k&1)==0) m=min(m,D[k--]); p>>=1; k>>=1; } if(p==k) m=min(m,D[p]); return m; } // MaxTree z "Algorytmiki praktycznej" Piotra Sta�czyka int main () { s = M; scanf("%d",&n); N = n + M; for (int i = M; i < N; ++i) scanf("%d%d",&C[i],&D[i]); for (int i = M - 1; i > 0; --i) C[i] = max(C[i << 1], C[(i << 1) | 1]); for (int i = N; i < DM; ++i) D[i] = INF; for (int i = M - 1; i > 0; --i) D[i] = min(D[i << 1], D[(i << 1) | 1]); for (int i = 1; i < DM; ++i) W[i] = -1; sposoby[n] = 1; nieujemne[n] = n; Set(n, 0); for (int i = 0; i < n; ++i) liczba[i] = -1; for (int i = n - 1; i >= 0; --i) { a = 0; b = n; poprzednik = i; for (int j = i + 1; j <= n; ) { j = nieujemne[j]; if (liczba[i] > wynik[j] + 1) break; int g = j + s; while (W[g] < liczba[i] - 1) { if (g & 1) g++; else (g >>= 1); } while (g < s) { g <<= 1; if (W[g] < liczba[i] - 1) g |= 1; } j = g - s; a = max(a, Find1(poprzednik, j - 1)); b = min(b, Find2(poprzednik, j - 1)); poprzednik = j; if (a > b) break; if (b < j - i) break; if (j - i < a) { j = a + i; continue; } if (liczba[j] >= liczba[i]) { liczba[i] = liczba[j] + 1; sposoby[i] = sposoby[j]; } else { sposoby[i] += sposoby[j]; if (sposoby[i] >= 1000000007) sposoby[i] -= 1000000007; } j++; } if (liczba[i] == -1) nieujemne[i] = nieujemne[i + 1]; else nieujemne[i] = i; if (liczba[i] > wynik[i + 1]) wynik[i] = liczba[i]; else wynik[i] = wynik[i + 1]; if (liczba[i] != -1) Set(i, liczba[i]); } if (liczba[0] == -1) printf("NIE\n"); else printf("%d %d\n", liczba[0], sposoby[0]); return 0; } |
English