Cod sursa(job #3339725)

Utilizator Cezar2009Cezar Mihai Titihazan Cezar2009 Data 9 februarie 2026 17:57:46
Problema Arbori de intervale Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.59 kb
//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;
}