Cod sursa(job #108223)

Utilizator dominoMircea Pasoi domino Data 21 noiembrie 2007 22:06:27
Problema NKPerm Scor Ascuns
Compilator cpp Status done
Runda Marime 2.57 kb
#include <stdio.h>
#include <map>

using namespace std;

#define FIN "nkperm.in"
#define FOUT "nkperm.out"
#define MAX_N 25
#define MAX_K 10
#define BASE 21
#define VAL(i) ((cfg/pow[i])%BASE)
#define INF (1ll<<55)
#define ll long long

int N, K, T, cnt[MAX_N], pow[MAX_K];
map<int, ll> mem;

int encode(int cnt[], int prev)
{
    int i, cnt2[MAX_K] = {0}, ret = 0;

    for (i = 1; i <= N; ++i)
        cnt2[cnt[i]]++;
    for (i = 0; i <= K; ++i)
        ret += cnt2[i]*pow[i];
    ret += cnt[prev]*pow[K+1];
    return ret;
}

ll count(int cfg)
{
    char i, v, vv;
    int new_cfg; ll ret = 0;

    if (mem.find(cfg) != mem.end())
        return mem[cfg];
    if (VAL(K) == N) return 1;

    char last = VAL(K+1);
    for (i = 0; i < K; ++i)
    {
        if (!(v = VAL(i))) continue;
        vv = VAL(i+1);
        new_cfg = cfg-pow[i]+pow[i+1]+(i+1-last)*pow[K+1];
        ret += (ll)(v-(last == i))*count(new_cfg);
        if (ret >= INF) { ret = INF; break; }
    }

    mem[cfg] = ret;
    return ret;
}

int main(void)
{
    int i, j, prev;
    ll x, t, ret; char op;

    freopen(FIN, "r", stdin);
    freopen(FOUT, "w", stdout);

    pow[0] = 1;
    for (i = 1; i < MAX_K; ++i)
        pow[i] = pow[i-1]*BASE;

    for (scanf("%d %d %d", &N, &K, &T); T; --T)
    {
        scanf(" %c", &op);
        if (op == 'A')
        {
            memset(cnt, 0, sizeof(cnt));
            for (prev = -1, ret = 1, i = 0; i < N*K; ++i)
            {
                scanf("%lld", &x);
                for (j = 1; j < x; ++j)
                {
                    if (j == prev || cnt[j] == K) continue;
                    cnt[j]++;
                    ret += count(encode(cnt, j));
                    cnt[j]--;
                }
                cnt[prev = x]++;
            }
            printf("%lld\n", ret);
        }
        else
        {
            scanf("%lld", &x);
            memset(cnt, 0, sizeof(cnt));
            for (prev = -1, ret = i = 0; i < N*K; ++i)
            {
                for (j = 1; j <= N; ++j)
                {
                    if (j == prev || cnt[j] == K) continue;
                    cnt[j]++;
                    t = count(encode(cnt, j));
                    if ((ret += t) >= x)
                    {
                        ret -= t;
                        printf("%d ", j);
                        break;
                    }
                    cnt[j]--;
                }
                prev = j;
            }
            printf("\n");
        }
    }

    return 0;
}