Cod sursa(job #2006670)

Utilizator Mircea_DonciuDonciu Mircea Mircea_Donciu Data 31 iulie 2017 11:25:36
Problema NKPerm Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.62 kb
#include <cstdio>
#include <map>
using namespace std;

const int N = 20;
const int BASE = N+1;
const int K = 8;
const long long REZ = ((long long)1) << 55;

int n,k,t;
map<int, long long> m;

int code ( int f[], int last ) {
    int pw = 1, rez = 0;
    for (int i = 0; i <= k; ++i, pw *= BASE) rez += pw*f[i];
    rez += pw*last;
    return rez;
}

void decode ( int code, int f[], int &last ) {
    int pw = 1;
    for (int i = 0; i <= k; ++i, pw *= BASE) f[i] = (code/pw) % BASE;
    last = (code/pw) % BASE;
}

long long count ( int conf ) {
    if (m.find(conf) != m.end())
        return m[conf];
    int f[K], last;
    decode(conf,f,last);
    if (f[0] == n) return 1;
    long long rez = 0;
    for (int i = 1; i <= k; ++i) {
        if (f[i] != 0) {
            --f[i]; ++f[i-1];
            rez += (f[i] + (i != last)) * count(code(f,i-1));
            if (rez > REZ) {
                rez = REZ;
                break;
            }
            ++f[i]; --f[i-1];
        }
    }
    m[conf] = rez;
    return rez;
}

void a() {
    int ap[N];
    long long rez = 1;
    int last = -1, x;
    for (int i = 0; i < n; ++i) ap[i] = k;
    for (int i = 0; i < n*k; ++i) {
        scanf("%d",&x);
        --x;
        for (int j = 0; j < x; ++j) {
            if (ap[j] > 0 && j != last) {
                --ap[j];
                int f[K];
                memset(f,0,sizeof(f));
                for (int t = 0; t < n; ++t) ++f[ap[t]];
                rez += count(code(f,ap[j]));
                ++ap[j];
            }
        }
        --ap[x];
        last = x;
    }
    printf("%lld\n",rez);
}

void b() {
    int ap[N];
    int last = -1;
    long long x;
    scanf("%lld",&x);
    for (int i = 0; i < n; ++i) ap[i] = k;
    for (int i = 0; i < n*k; ++i) {
        int j;
        long long s = 0;
        for (j = 0; j < n; ++j) {
            if (ap[j] > 0 && j != last) {
                --ap[j];
                int f[K];
                memset(f,0,sizeof(f));
                for (int t = 0; t < n; ++t) ++f[ap[t]];
                long long y = count(code(f,ap[j]));
                ++ap[j];
                if (s + y >= x) break;
                s += y;
            }
        }
        x -= s;
        --ap[j];
        printf("%d ",j+1);
        last = j;
    }
    printf("\n");
}

int main() {
    freopen("nkperm.in","rt",stdin);
    freopen("nkperm.out","wt",stdout);
    scanf("%d %d %d",&n,&k,&t);
    for (int i = 0; i < t; ++i) {
        char cmd;
        scanf(" %c ",&cmd);
        if (cmd == 'A')
            a(); else
            b();
    }
}