Cod sursa(job #467059)

Utilizator savimSerban Andrei Stan savim Data 28 iunie 2010 11:13:49
Problema Pod Scor 65
Compilator cpp Status done
Runda Stelele Informaticii 2010, clasele X-XII, Ziua 2 Marime 2.48 kb
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

#define MAX_M 1010
#define MAX_K 30
#define prim 9901

int n, m, k, poz;
int c[MAX_K], d[MAX_K];
int obst[MAX_M];

int mat[MAX_K][MAX_K], init[MAX_K][MAX_K], aux[MAX_K][MAX_K];

void inm_mat(int put) {
	if (put == 1)
		return;

	inm_mat(put / 2);

	memset(aux, 0, sizeof(aux));

	for (int t = 1; t <= k; t++)
		for (int i = 1; i <= k; i++)
			for (int j = 1; j <= k; j++)
            	aux[i][j] = (aux[i][j] + mat[i][t] * mat[t][j]) % prim;

	for (int i = 1; i <= k; i++)
		for (int j = 1; j <= k; j++)
			mat[i][j] = aux[i][j];

	if (put % 2 == 1) {
		memset(aux, 0, sizeof(aux));

		for (int t = 1; t <= k; t++)
			for (int i = 1; i <= k; i++)
				for (int j = 1; j <= k; j++)
					aux[i][j] = (aux[i][j] + mat[i][t] * init[t][j]) % prim;

		for (int i = 1; i <= k; i++)
			for (int j = 1; j <= k; j++)
				mat[i][j] = aux[i][j];
	}
}

void solve(int diff, int poz) {
    for (int j = 1; j < k; j++)
        init[j][j + 1] = 1;
    init[k][1] = init[k][k] = 1;

	for (int i = 1; i <= k; i++)
		for (int j = 1; j <= k; j++)
			mat[i][j] = init[i][j];

	inm_mat(diff);

	memset(d, 0, sizeof(d));	
	for (int i = 1; i <= k; i++)
		for (int j = 1; j <= k; j++)
			d[i] = (d[i] + c[j] * mat[i][j]) % prim;

	for (int i = 1; i <= k; i++)
		c[i] = d[i];
}

inline int free_cell(int x) {
	int st = 0, dr = m + 1, mid = 0;

	while (st + 1 < dr) {
    	mid = (st + dr) / 2;

		if (obst[mid] < x)
			st = mid;
		else
			if (obst[mid] > x)
				dr = mid;
			else
				return 0;
	}

	return 1;
}

void write_sol() {
	for (int j = 1; j <= k; j++)
	    if (poz + j - 1 == n) {
    	    printf("%d\n", c[j]);
			return;
        }
}

int main() {
	freopen("pod.in", "r", stdin);
	freopen("pod.out", "w", stdout);

	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= m; i++)
		scanf("%d", &obst[i]);
	sort(obst + 1, obst + m + 1);

	int ok = 1;
	for (int i = 1; i < k; i++)
		if (free_cell(i))
			c[i] = ok;
		else
	    	ok = 0;
	if (free_cell(k))
		c[k] = 1 + ok;

	obst[m + 1] = n + 1; poz = 1;
	int i = 1;
	while (i <= m) {
		while (i <= m && obst[i] <= poz + k) {
			if (free_cell(poz + k))
				c[k + 1] = (c[k] + c[1]) % prim;
			for (int j = 1; j <= k; j++)
				c[j] = c[j + 1];
			c[k + 1] = 0;

			poz++;
			if (obst[i] < poz)
				i++;

			if (poz + k - 1 >= n) {
				write_sol();
				return 0;
	        }
		}

      	solve(obst[i] - obst[i - 1] - k - 1, obst[i]);
		poz = obst[i] - k;

		if (poz + k - 1 >= n) {
        	write_sol();
			return 0;
		}
	}

	return 0;
}