Cod sursa(job #112367)

Utilizator GiggityGlen Quagmire Giggity Data 4 decembrie 2007 21:11:21
Problema NKPerm Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.76 kb
#include<stdio.h>
#include<map>
#include<string>

using namespace std;

void sub(long long &u, int poz);
void add(long long &u, int poz);
void csA();
void csB();
long long count(long long u);
long long get(long long u, int x);

int N, K, T, P[128], cate[32], sol[128];
long long pw[8], rezz, MAX;

map<long long, long long> M;

int main()
{
	char ch;
	int i;

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

	scanf("%d%d%d ", &N, &K, &T);
	pw[0] = 1;
	for(ch = 1; ch <= K + 2; ch++)
		pw[ch] = (long long) pw[ch - 1] * (N + 1);

	MAX = 1 << 11;
	MAX = MAX * MAX * MAX * MAX * MAX;

	for(; T--;)
	{
		scanf("%c ", &ch);
		if(ch == 'A')
		{
			for(i = 0; i < N * K; i++)
				scanf("%d ", P + i);

			csA();
		}
		else
		{
			scanf("%lld ", &rezz);
			csB();
			for(i = 0; i < N * K; i++)
				printf("%d ", sol[i]);
			printf("\n");
		}
	}
	return 0;
}

void csA()
{
	int i, j;
	long long rez, u;

	u = N;

	memset(cate, 0, sizeof(cate));
	rez = 0;

	for(i = 0; i < N * K; i++)
	{
		for(j = 1; j < P[i]; j++)
		if((!i || j != P[i - 1]) && cate[j] < K)
		{
			add(u, cate[j]);
			rez += count(get(u, cate[j] + 1));
			sub(u, cate[j] + 1);
		}
		add(u, cate[P[i]]);
		cate[P[i]]++;
	}

	printf("%lld\n", rez + 1);
}

void add(long long &u, int poz)
{
	u -= pw[poz];
	u += pw[poz + 1];
}

void sub(long long &u, int poz)
{
	u -= pw[poz];
	u += pw[poz - 1];
}

long long get(long long u, int x)
{
	u += (long long) pw[K + 1] * x;
	return u;
}

long long count(long long u)
{
	long long z;
	map<long long, long long>::iterator ii;

	ii = M.find(u);
	if(ii != M.end())
		return ii->second;

	
	//toate numerele au fost alese de exact K ori
	z = u / pw[K];
	z %= N + 1;
	if(z == N)
	{
		M[u] = 1;
		return 1;
	}
	//

	int i;
	long long last;
	long long rez = 0;

	last = u / pw[K + 1];

	for(i = 0; i < K; i++)
	{
		z = u / pw[i];
		z %= N + 1;

		if(z)
		{
			u -= pw[i];
			u += pw[i + 1];
			u -= (long long) last * pw[K + 1];
			u += (long long) (i + 1) * pw[K + 1];

			if(last == i)
				rez += (z - 1) * count(u);
			else rez += z * count(u);
		
			u += pw[i];
			u -= pw[i + 1];
			u -= (long long) (i + 1) * pw[K + 1];
			u += (long long) last * pw[K + 1];

			if(rez >= MAX)
			{
				M[u] = MAX;
				return MAX;
			}
		}
	}

	M[u] = rez;
	return rez;
}

void csB()
{
	int i, j;
	long long rez, u, x;

	memset(cate, 0, sizeof(cate));
	u = N;
	rez = 0;

	for(i = 0; i < N * K; i++)
	{
		for(j = 1; j <= N; j++)
		if(cate[j] < K && (!i || j != sol[i - 1]))
		{
			add(u, cate[j]);
			x = count(get(u, cate[j] + 1));
			if(rez + x >= rezz)
				break;
			rez += x;
			sub(u, cate[j] + 1);
		}
		sol[i] = j;
		cate[j]++;
	}
}