周赛84——G:组合数+贡献法的经典考点

蒟蒻的第二篇题解,以后尝试在牛客发表我这个蒟蒻的理解(大佬勿喷)

改试卷改到8点半,没来得及打了/(ㄒoㄒ)/~~,

组合计数最常考的就是搭配贡献法,如果报名了寒假训练营的可以去把寒假5的H题(稍微比这题有点难度,当时wa了6次)再写一遍。

这题因为要全排序,然后又让我们求每两个数的差,我们可以先这样考虑:

1:对于单独的1个数:ai, 怎么算贡献比较好算?(因为求的是绝对值,直接算的话函数极值点太多了)

2:算出一个贡献后,我们有多少种情况?(注:题目规定贡献是:ai 和 ai+1)

对于问题1:我们求ai的贡献,无非就是和所有数字去组合一下(也就是 ai 和 a1, a2, a3 ...... an (除了自己))

这个怎么算?有人会说直接用一个计数器,然后用 sum - ai 就好了

但是我们求的是绝对值,这么算显然是比正确小,因为对于 ak (ak < ai)来说,这么算就是负数,而取绝对值就是正数。

那么怎么算好呢?

我们稍加思考就会发现,我们只要把数组排序后,这个问题就解决啦!

因为这样一来就是个升序数组,这样就可以用前缀和维护了;

对于比 ai 小的数, 我们的贡献显然是 (i - 1)ai - s[i - 1];

对于比 ai 大的数, 我们的贡献显然是 s[n] - s[i] - (n - i)ai;

这样第一个问题就解决了

对于问题2:对于我们这个贡献,我们可以把这两坨玩意放到任何一个地方,也就是捆绑;

(这里不能交换,因为交换之后我们的贡献就变化了)

然后对于剩余的 n - 2 个数字可以随便排列

那么我们的情况数量就是 (n - 2)! * (n - 1) = (n - 1)!

最后整个序列的全排列的总数是 n !

答案就是把贡献 ans * (n - 1)!/ n!= ans / n

(别忘记给前缀和取模,这里wa了2次)

#include<bits/stdc++.h>

#define lc p << 1
#define rc p << 1 | 1
#define lowbit(x) x & -x
#define inv(x) qmi(x, P - 2)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef unsigned __int128 ulll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<lll,lll> pLL;
const ll N = 2e5 + 10, inf = 0x3f3f3f3f, INF = 0x3f3f3f3f3f3f, P = 1e9 + 7;
int dx[] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[] = {0, 1, 0, -1, -1, 1, -1, 1};

int T = 1;
ll qmi(ll a, ll b){
    ll res = 1;
    while(b){
        if(b & 1) res = res * a % P;
        b >>= 1;
        a = a * a % P;
    }
    return res;
}
ll gcd(ll a, ll b){
    return b ? gcd(b, a % b) : a;
}

void solve(){
    int n;
    cin >> n;
    vector<ll> a(n + 10), s(n + 10);
    for(int i = 1; i <= n; i ++) cin >> a[i];
    sort(a.begin() + 1, a.begin() + 1 + n);

    for(int i = 1; i <= n; i ++) s[i] = (s[i - 1] + a[i]) % P;
    ll ans = 0;
    for(ll i = 1; i <= n; i ++){
        ll pre = (i - 1) * a[i] % P - s[i - 1];
        if(pre < 0) pre = (pre + P) % P;
        ll last = (s[n] - s[i] - ((n - i) * a[i] % P));
        if(last < 0) last = (last + P) % P;
        ans = (ans + pre + last) % P; 
    }   
    cout << ans * inv(n) % P << '\n';
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    //cin >> T;
    while(T --){
        solve();
    }
    return 0;
}

全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务