Codeforces 1284C New Year and Permutation (R1700)
問題
整数が与えられます。長さの順列のスコアを
を満たすような組の個数
とします。長さの全ての順列のスコアの合計をで求めてください。
制約
- は素数
考察
という条件について
部分列の長さを、最小値をとおきます。この部分列が条件を満たすとすると、最大値はです。この部分列の長さをにするためにはあと個の要素を追加しなければなりませんが、より大きくより小さい要素が個しか残っていないので、追加する数は一意に定まります。結局この条件は、が連続する整数からなる、という条件だと分かります。
全ての順列について部分列の個数を数える代わりに、各部分列が何回数えられるかを考えます。ある部分列が同じ順列に二度以上含まれることはないので、その部分列を含むような順列の個数が求めるものです。
まずは具体的な例で考えてみましょう。例えばのとき、を含む順列がいくつあるかを考えます。これはの位置が通り、各場合について残りの要素の並べ方が通りあるのであることが分かります。
これを全ての条件を満たす部分列について求めて足し合わせたものが答えです。この値は部分列の長さだけによるので、同じ長さの部分列をまとめて数えることができます。長さの条件を満たす部分列は通りあるので、結局答えはです。
#include<bits/stdc++.h> using namespace std; using Lint=long long; int main() { int n,mod; cin>>n>>mod; vector<int> fact(n+1); fact[0]=1; for(int i=1;i<=n;i++) fact[i]=(Lint)i*fact[i-1]%mod; int ans=0; for(int k=1;k<=n;k++){ ans+=(Lint)(n-k+1)*(n-k+1)%mod*fact[k]%mod*fact[n-k]%mod; ans%=mod; } cout<<ans<<endl; return 0; }
感想
「すべての場合について~を求めて足し合わせた結果を求める」という問題は、各要素の寄与を考えるのが典型です。すべての要素について考えられない場合は、うまくまとめて数える必要があります。全探索できるパラメーターを考えたら長さが見つかって、解けました。