mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #297 (Div. 2) E.Anya and Cubes

なんとなく初めて解く部類の問題な気がする。

問題:http://codeforces.ru/problemset/problem/525/E

解法:数列a[]のn個のうちの最初のn/2個を全探索して取りうる値及びその値を取る場合の数を調べる。次にn/2個からn個にある数を全探索して同じことをする。以上の情報から条件に合う場合の数を求める。
以下ソースコード

ll fact[20];

void init() {
    fact[0] = 1;
    for (int i = 1; i < 20; i++) fact[i] = fact[i-1] * i;
}

const int MAXN = 30;
const ll MAX = 1e16;
ll a[MAXN];
map<ll, ll> lcnt[MAXN], rcnt[MAXN];
int n, k;
ll S;

void ldfs(int cur, int nn, int kk, ll sum) {
    if (cur == nn) {
        if (sum <= MAX) lcnt[kk][sum]++;
        return;
    }
    if (kk > k || sum > S) return;
    ldfs(cur+1, nn, kk, sum);
    ldfs(cur+1, nn, kk, sum+a[cur]);
    if (a[cur] < 19) ldfs(cur+1, nn, kk+1, sum+fact[a[cur]]);
}
void rdfs(int cur, int nn, int kk, ll sum) {
    if (cur == nn) {
        if (sum <= MAX) rcnt[kk][sum]++;
        return;
    }
    if (kk > k || sum > S) return;
    rdfs(cur+1, nn, kk, sum);
    rdfs(cur+1, nn, kk, sum+a[cur]);
    if (a[cur] < 19) rdfs(cur+1, nn, kk+1, sum+fact[a[cur]]);
}

int main() {
    init();
    cin >> n >> k >> S;
    for (int i = 0; i < n; i++) cin >> a[i];
    int nn = n/2;
    ldfs(0, nn, 0, 0);
    rdfs(nn, n, 0, 0);
    ll ans = 0;
    for (int kk = 0; kk <= k; kk++) {
        for (auto el : lcnt[kk]) {
            ll lsum = el.first;
            for (int kkk = 0; kkk <= k-kk; kkk++) {
                if (rcnt[kkk].find(S-lsum) != rcnt[kkk].end()) {
                    ans += rcnt[kkk][S-lsum] * lcnt[kk][lsum];
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}