srupのメモ帳

競プロで解いた問題や勉強したことを記録していくメモ帳

yukicoder No.118 門松列(2)

問題

問題概要

門松列になる組み合わせを求める問題。

解法

この問題の注意点は並び順が違っても、同じ竹の組み合わせなら同じとカウントするという点である。よって、門松列になる竹の組み合わせが何通りあるかを求めるには、3本の竹が異なるようにとることができる竹の長さの組み合わせが何通りあるか求めればいい。よって、まず、それぞれの竹の長さが何本ずつあるかをcnt[]に記録して、次に3重ループの全探索で、条件を満たす3本の竹の長さの組み合わせを出す。つぎに、もし同じ竹の長さのものが複数ある場合は、それらは区別することができるので、その分だけかけてあげればいい。cnt[i] * cnt[j] * cnt[k]の部分のこと。

ミス

なし。

コード

conbination関数作ってるけど、ただ3C3=1をやるだけだから関係ない。

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(n);i++)

int n, a[100010];
const int mod = 1e9 + 7;

ll conbination(int x){
    ll ret = x * (x - 1) * (x - 2) / 6;
    return ret;
}

int main(void){
    cin >> n;
    rep(i, n) cin >> a[i];

    ll cnt[110];
    rep(i, 110) cnt[i] = 0;
    rep(i, n){
        cnt[a[i]]++;
    }

    ll ans = 0;
    for (int i = 1; i <= 100; ++i){
        for (int j = i + 1; j <= 100; ++j){
            for (int k = j + 1; k <= 100; ++k){
                if(cnt[i] != 0 && cnt[j] != 0 && cnt[k] != 0){//すべての長さの竹があるとき
                    // (ans += conbination(3) * cnt[i] * cnt[j] * cnt[k]) %= mod;
                    (ans += 1 * cnt[i] * cnt[j] * cnt[k]) %= mod;
                }
            }
        }
    }

    printf("%lld\n", ans);
    return 0;
}