Cod sursa(job #109375)

Utilizator mugurelionutMugurel-Ionut Andreica mugurelionut Data 25 noiembrie 2007 10:34:40
Problema NKPerm Scor 80
Compilator cpp Status done
Runda preONI 2008, Runda 1, Clasele 11-12 Marime 4.26 kb
#include <stdio.h>
#include <string.h>

#include <map>
#include <vector>
using namespace std;

#define BIGINT long long //__int64 // long long
#define fmt "%lld" //"%I64d" //"%lld"

#define NMAX 21
#define KMAX 6
#define MAXSTATES 54000

map<int, int> hmap;
int state[MAXSTATES][KMAX], perm[NMAX * KMAX];
BIGINT nperm[MAXSTATES][KMAX], maxperm, permnum, np;
int cnt[KMAX], nap[NMAX], nstates, sgroup;
int N, K, T, i, k, nk, sum, hv, spoz;
char top;

inline int hash(int cnt[])
{
	int i, h = 0;

	for (i = 0; i <= K; i++)
		h = (h << 5) + cnt[i];

	return h;
}

void genStates(int niv)
{
	int x;

	if (niv > K)
	{
		if (sum == N)
		{
			nstates++;
			memcpy(state[nstates], cnt, sizeof(cnt));
			hmap[hash(cnt)] = nstates;
		}
	}
	else
	{
		for (x = 0; x <= N; x++)
		{
			cnt[niv] = x;
			sum += x;

			if (sum <= N)
				genStates(niv + 1);

			sum -= x;
			cnt[niv] = 0;
		}
	}
}

void compute(int st, int special_group)
{
	int i, hv, spoz;
	BIGINT vaux;

	if (nperm[st][special_group] >= 0)
		return;

	if (state[st][0] == N)
	{
		nperm[st][special_group] = 1;
		return;
	}

	memcpy(cnt, state[st], sizeof(cnt));
	nperm[st][special_group] = 0;

	for (i = 1; i <= K; i++)
		if (state[st][i] > 0)
		{
			cnt[i]--;
			cnt[i - 1]++;

			hv = hash(cnt);
			spoz = hmap[hv];

			if (spoz > 0)
			{
				if (nperm[spoz][i - 1] < 0)
					compute(spoz, i - 1);

				if (i == special_group)
					vaux = state[st][i] - 1;
				else
					vaux = state[st][i];

				if (vaux > 0)
				{
					if (((maxperm - nperm[st][special_group]) / vaux) > nperm[spoz][i - 1])
						nperm[st][special_group] += nperm[spoz][i - 1] * vaux;
					else
						nperm[st][special_group] = maxperm;
				}
			}
			else
			{
				fprintf(stderr, "?\n");
			}

			cnt[i - 1]--;
			cnt[i]++;
		}
}

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

	scanf("%d %d %d", &N, &K, &T);

	nk = N * K;
	sum = 0;
	nstates = 0;
	genStates(0);

	for (i = 1; i <= nstates; i++)
		for (k = 0; k <= K; k++)
			nperm[i][k] = -1;

	maxperm = 1;
	for (i = 1; i <= 57; i++)
		maxperm = maxperm * 2;

	for (i = 1; i <= nstates; i++)
		for (k = 0; k <= K; k++)
			compute(i, k);

	/*
	printf("nstates = %d\n", nstates);
	for (i = 1; i <= nstates; i++)
		for (k = 0; k <= K; k++)
		{
			printf("%d,%d:", i, k);
			printf(fmt, nperm[i][k]);
			printf("\n");
		}

	return 0;
	*/

	while (T--)
	{
		scanf(" %c", &top);

		if (top == 'A')
		{
			perm[0] = 0;
			for (i = 1; i <= nk; i++)
				scanf("%d", &perm[i]);

			memset(cnt, 0, sizeof(cnt));
			cnt[K] = N;
			
			nap[0] = 0;
			for (i = 1; i <= N; i++)
				nap[i] = K;

			permnum = 0;

			for (i = 1; i <= nk; i++)
			{
				for (k = 1; k < perm[i]; k++)
				{
					if (k == perm[i - 1] || nap[k] == 0)
						continue;

					// pune elementul k pe pozitia i

					cnt[nap[k]]--;
					cnt[nap[k] - 1]++;

					hv = hash(cnt);
					spoz = hmap[hv];

					if (spoz > 0)
					{
						permnum += nperm[spoz][nap[k] - 1];
					}
					else
						fprintf(stderr, "??\n");

					cnt[nap[k] - 1]--;
					cnt[nap[k]]++;
				}

				// elimina elementul perm[i]
				cnt[nap[perm[i]]]--;
				nap[perm[i]]--;
				cnt[nap[perm[i]]]++;
			}

			printf(fmt, permnum + 1);
			printf("\n");
		}
		else
		{
			scanf(fmt, &permnum);

			// determina elementele permutarii unul cate unul, de la primul la ultimul

			memset(cnt, 0, sizeof(cnt));
			cnt[K] = N;
			
			nap[0] = 0;
			for (i = 1; i <= N; i++)
				nap[i] = K;

			perm[0] = 0;

			for (i = 1; i <= nk; i++)
			{
				for (k = 1; k <= N; k++)
				{
					if (k == perm[i - 1] || nap[k] == 0)
						continue;

					cnt[nap[k]]--;
					cnt[nap[k] - 1]++;

					hv = hash(cnt);
					spoz = hmap[hv];

					if (spoz > 0)
					{
						np = nperm[spoz][nap[k] - 1];

						if (np >= permnum)
						{
							perm[i] = k;
							nap[k]--;
							break;
						}
						else
							permnum -= np;
					}
					else
					{
						fprintf(stderr, "???\n");
					}

					cnt[nap[k] - 1]--;
					cnt[nap[k]]++;
				}
			}

			printf("%d", perm[1]);

			for (i = 2; i <= nk; i++)
				printf(" %d", perm[i]);

			printf("\n");
		}
	}

	return 0;
}