結果
問題 | No.125 悪の花弁 |
ユーザー | codershifth |
提出日時 | 2015-10-23 01:33:03 |
言語 | C++11 (gcc 11.4.0) |
結果 |
AC
|
実行時間 | 87 ms / 5,000 ms |
コード長 | 4,951 bytes |
コンパイル時間 | 1,561 ms |
コンパイル使用メモリ | 168,188 KB |
実行使用メモリ | 34,944 KB |
最終ジャッジ日時 | 2024-07-22 23:02:32 |
合計ジャッジ時間 | 3,032 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 76 ms
34,304 KB |
testcase_01 | AC | 83 ms
34,816 KB |
testcase_02 | AC | 87 ms
34,816 KB |
testcase_03 | AC | 84 ms
34,944 KB |
testcase_04 | AC | 74 ms
34,304 KB |
testcase_05 | AC | 76 ms
34,432 KB |
ソースコード
#include <bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; #define FOR(i,a,b) for(int (i)=(a);i<(int)(b);i++) #define REP(i,n) FOR(i,0,n) #define RANGE(vec) (vec).begin(),(vec).end() template<typename T> T gcd(T a, T b) { if ( std::abs(a) < std::abs(b) ) std::swap(a,b); if ( b == 0 ) return a; return gcd(b, a%b); } class Fact { std::vector<long long> inv_; std::vector<long long> fact_; std::vector<long long> factr_; public: // O(maxN) Fact(int maxN, long long P) { long long ModP = P; inv_.resize(maxN+1,0); fact_.resize(maxN+1,0); factr_.resize(maxN+1,0); inv_[1] = fact_[0] = factr_[0] = 1; for (int i = 2; i <= maxN; ++i) inv_[i] = inv_[ModP % i] * (ModP - ModP/i) % ModP; for (int i = 1; i <= maxN; ++i) { fact_[i] = fact_[i-1]*i % ModP; factr_[i] = factr_[i-1]*inv_[i] % ModP; } } long long fact(long long n) { return fact_[n]; } long long factr(long long n) { return factr_[n]; } long long inv(long long n) { return inv_[n]; } }; using namespace std; const int Mod = (int)(1E+9)+7; class EvilPetal { public: void solve(void) { const int maxN = (int)1E+6; int K; cin>>K; vector<int> C(K); int T = 0; REP(i,K) { cin>>C[i]; T += C[i]; } // C[i] 全てをならべて作った花弁は T 回転させると元に戻る // 花弁の作り方のうち k 回転させて元に戻るものを考える // すると T%k==0 になるはず。 // つまり要素 k 個をならべたグループを考えてそれが T/k の周期をもつということ。 // // [abcde][abcde]...[abcde] // <--k--> // <--------- T ----------> // // 一つのグループに C[i] の色が j 個現れるとすると、C[i] 全て使いきらないといけないので // // C[i] == (T/k) * j ... (※) // // となる。 よってグループの周期 (T/k) が取りうる値は全ての C[i] の最大公約数の約数となる。 // あとは [abcde] の取りうる組み合わせを計算すればよい。 // int g = C[0]; FOR(i,1,K) g = gcd(g, C[i]); vector<int> gsize; // 各周期に対応するグループの長さを格納 for (int pd = 1; pd*pd <= g ; ++pd) { if ( g % pd != 0 ) continue; gsize.push_back(T/pd); if (g/pd != pd) gsize.push_back(T/(g/pd)); } // 周期が pd のグループ [abcd..] のとり得る組み合わせは // // (T/pd)!/Π(C[i]/pd)! // // となる。(※より C[i]/pd が一つのグループで使われる C[i] の色の数) // // [abcd] を考えるときに [abab] のようにグループの長さの約数に // なるようなサブグループによる繰り返し // は重複してかぞえられてしまうのでその分を引けば良い // Fact f(maxN, Mod); // 1/n, n!, 1/n! (mod P) 計算モジュール vector<ll> num(maxN+1,0); // 重複削除のためグループの長さが短いものから数える ll tot = 0; sort(RANGE(gsize)); REP(i,gsize.size()) { int gs = gsize[i]; ll cnt = f.fact(gs); REP(j,K) // period = T/gs cnt = cnt * f.factr(C[j]/(T/gs)) % Mod; // 計算済みのサブグループによる重複を削除する REP(j,i) { // 長さが約数になっているサブグループ if (gs % gsize[j] == 0) { cnt -= num[gsize[j]]; (cnt += Mod) %= Mod; } } num[gs] = cnt; // [abcd][abcd]...[abcd] // ^ // [abcd][abcd]...[abcd] // ^ // スタート位置の固定の仕方は gs 通りあるのでその分の重複を避けるため * 1/gs (tot += num[gs]*f.inv(gs)%Mod) %= Mod; } cout<<tot<<endl; } }; #if 1 int main(int argc, char *argv[]) { ios::sync_with_stdio(false); auto obj = new EvilPetal(); obj->solve(); delete obj; return 0; } #endif