Pagini recente » Borderou de evaluare (job #937101) | Borderou de evaluare (job #928131) | Cod sursa (job #3339725)
//https://infoarena.ro/problema/mexitate
//#pragma GCC optimize("O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("inline")
//#define _USE_MATH_DEFINES
//#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
//#include <vector>
//#include <cstring>
//#include <cmath>
//#include <bitset>
//#include <queue>
//#include <stack>
//#include <utility>
//#include <algorithm>
//#include <string>
//#include <map>
//#include <unordered_map>
//#include <set>
//#include <unordered_set>
//#include <cstdint>
//#include <climits>
//#include <iomanip>
//#include <cstdio>
//#include <tuple>
using namespace std;
ifstream fin("mexitate.in");
ofstream fout("mexitate.out");
const int NMMAX = 400000;
const int MOD = 1000000007;
const int SQRT = 632;
int mat[NMMAX];
int fr[NMMAX];
int bat[SQRT + 1];
int n, m, k, l;
// n lini, m coloane ale dreptunghiului initial
// k lini, l coloane ale dreptunghiului ales
int rezultat()
{
int i = 0, rez = 0;
while(bat[i] == SQRT)
++i;
rez = i * SQRT + 1;
while (fr[rez])
++rez;
return rez;
}
void adaugare(int pos)
{
++fr[pos];
if (fr[pos] == 1)
{
int batPos = (pos - 1) / SQRT;
++bat[batPos];
}
}
void scoatere(int pos)
{
--fr[pos];
if (fr[pos] == 0)
{
int batPos = (pos - 1) / SQRT;
--bat[batPos];
}
}
bool dreapta(int& x, int& y) // si x + k - 1, y + l - 1 capetele jos dreapta
{
if (y + l > m) // daca nu are loc unde sa se duca in dreapta
return false;
// trebuie sa scoatem coloana y
for (int i = x; i <= x + k - 1; ++i)
scoatere(mat[i * m + y]);
// trebuie sa adaugam coloana y + l - 1 + 1 = y + l
for (int i = x; i <= x + k - 1; ++i)
adaugare(mat[i * m + y + l]);
++y;
return true;
}
bool stanga(int& x, int& y) // si x + k - 1, y + l - 1 capetele jos dreapta
{
if (y - 1 < 1) // daca nu are loc unde sa se duca in stanga
return false;
// trebuie sa scoatem coloana y + l - 1
for (int i = x; i <= x + k - 1; ++i)
scoatere(mat[i * m + y + l - 1]);
// trebuie sa adaugam coloana y - 1
for (int i = x; i <= x + k - 1; ++i)
adaugare(mat[i * m + y - 1]);
--y;
return true;
}
bool jos(int& x, int& y) // si x + k - 1, y + l - 1 capetele jos dreapta
{
if (x + k > n)
return false;
// trebuie sa scoatem linia x
for (int j = y; j <= y + l - 1; ++j)
--fr[mat[x * m + j]];
// trebuie sa adaugam linia x + k
for (int j = y; j <= y + l - 1; ++j)
++fr[mat[(x + k) * m + j]];
++x;
return true;
}
int main()
{
//ios_base::sync_with_stdio(false);
//cin.tie(nullptr);
//cout.tie(nullptr);
int i, j;
int64_t rez = 1;
fin >> n >> m >> k >> l;
for (i = 1; i <= n; ++i)
for (j = 1; j <= m; ++j)
fin >> mat[i * m + j];
/*for (i = 1; i <= n; ++i)
{
for (j = 1; j <= m; ++j)
cout << mat[i][j] << " ";
cout << "\n";
}*/
for (j = 1; j <= l; ++j) // ma duc in dreapta
{
// adaugam in dreapta fara sa scoatem nimic
for (int i = 1; i <= k; ++i)
++fr[mat[i * m + j]];
}
int x = 1, y = 1, dir = 0;
do
{
//cout << x << " " << y << " " << rezultat() << "\n";
rez = rez * rezultat() % MOD;
while ((dir == 0) ? dreapta(x, y) : stanga(x, y)) // ma pot duce in dreapta sau in stanga
{
//cout << x << " " << y << " " << rezultat() << "\n";
rez = rez * rezultat() % MOD;
}
dir = 1 - dir; // schimb directia
} while (jos(x, y)); // ma pot duce in jos
fout << rez << "\n";
fin.close();
fout.close();
return 0;
}