codeforces 938E MaxHistory 组合数学
生活随笔
收集整理的這篇文章主要介紹了
codeforces 938E MaxHistory 组合数学
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意
給出一個長為n的序列,對于這個序列的任意一個排列,求∑fa\sum f_a∑fa?的值。
題解
我們枚舉每一個aia_iai?然后,計算aia_iai?出現了多少次,然后把ai?numa_i*numai??num加入到ans里面。
考慮aia_iai?什么時候出現。
aia_iai?出現的位置前面的aja_jaj?必須嚴格小于aia_iai?,這樣aia_iai?才能被取到,而且aia_iai?后面一定要有比它大的數,這樣才能aia_iai?取到。
假設小于aia_iai?的數有mmm個,那么numm=∑r=0mCmr?r!?(n?1?r)!num_m = \sum_{r = 0}^mC_m^r*r!*(n-1-r)!numm?=∑r=0m?Cmr??r!?(n?1?r)!
整個的公式就是:
∑i=1nai?numi\sum_{i = 1}^na_i*num_i∑i=1n?ai??numi?
但這樣暴力求的話時間復雜度是O(n2)O(n^2)O(n2),因此必須運用公式變換上述式子,可以證明numinum_inumi?可以在O(1)O(1)O(1)的時間求出來,具體求解方法見下圖。
題解
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; #define pr(x) cout<<#x<<":"<<x<<endl const int maxn = 1e6+10; typedef long long ll; const ll mod = 1e9+7; ll a[maxn],fac1[maxn],fac2[maxn]; int n; int main(){scanf("%d",&n);for(int i = 0;i < n;++i)scanf("%lld",&a[i]);sort(a,a+n);fac1[0] = 1;fac2[n+1] = 1;fac2[n] = n;for(int i = 1;i <= n;++i)fac1[i] = fac1[i-1]*i%mod;for(int i = n-1;i >= 1;--i)fac2[i] = fac2[i+1]*i%mod;ll ans = 0;for(int i = 0,j = 1;i < n && a[i] != a[n-1];i = j){for(j = i;a[i] == a[j];j++);ll num = j-i;ans = (ans + num*((a[i]*fac1[n-i-1]%mod)*fac2[n-i+1]))%mod;}cout<<ans<<endl;return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的codeforces 938E MaxHistory 组合数学的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10月31是什么节日 你知道吗
- 下一篇: codeforces 940E Cash