ARC 128 F Game against Robot 题解

ARC 128 F Game against Robot 题解

一个很有意思的计数题。

首先观察给定序列能选择的牌需要满足什么性质。

很显然可以转变成网络流的模型,必须满足前\(2k\)个选择的个数不能超过\(k\)张牌。

考虑每张牌的贡献,假设当前为\(x\),可以将\(\geq x\)的看作1,\(<x\)的看作0 。

然后就转变成了\(0-1\)问题。

可以统计所有可能排列选择的\(1\)的和,也就是选择比\(x\)大的牌的总数。

可以将\(0\)看成\(-1\),pre为前缀和。

然后统计形如:

\[\sum_{pre}\lfloor \max(pre[1],pre[2],pre[3]...pre[n])\rfloor\\ =\sum_{z\geq 1} \sum_{pre}[\exists pre_i\geq 2z] \]

后面那个式子可以看作网格上移动需要触碰一条\(y-x=2z\)的直线。

是一个很经典的组合数。

时间复杂度为\(O(N)\)。

code:

#include<bits/stdc++.h>
#include<atcoder/all>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define rep(a,b) for(int a=0;a<b;++a)
#define LL long long
#define PB push_back
#define POB pop_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
using namespace atcoder;
using mint = modint998244353;
const int MAXN=1e6+1;
mint fact[MAXN],ifact[MAXN];
mint comb(int A,int B){
    return fact[A]*ifact[B]*ifact[A-B];
}
int a[MAXN],n;
mint cnt[MAXN];
mint tmp[MAXN];
int main(){
    fact[0]=1;
    rb(i,1,1000000) fact[i]=fact[i-1]*i;
    ifact[1000000]=1/fact[1000000];
    rl(i,1000000-1,0) ifact[i]=ifact[i+1]*(i+1);
    scanf("%d",&n);
    rb(i,1,n) scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    reverse(a+1,a+1+n);
    tmp[0]=1;
    mint ans=0;
    rb(k,1,n){
        if(k>=2) tmp[k]=tmp[k-2];
        tmp[k]+=comb(n,k);
        cnt[k]=comb(n,k)*k;
        int z=max(2,2*k-n+1);
        if(z%2==1) z++;
		if(k-z>=0)
        cnt[k]-=tmp[k-z];
        z=(z-2)/2;
        cnt[k]-=comb(n,k)*z;
        cnt[k]*=fact[k];
        cnt[k]*=fact[n-k];
        ans+=(cnt[k]-cnt[k-1])*a[k];
//        cout<<k<<" "<<cnt[k].val()<<" "<<endl;
    }
    cout<<ans.val()<<endl;
    return 0;
}
上一篇:求组合数


下一篇:阮文韬小组第四周学习小结