CF Round 1015 题解合集

here.

好像不难,问题是时间不够。

D

来搞笑的不是。

考虑二分答案,相当于是 \(\le mid\) 的数都要被删除,所以我们把这些位置标为 \(1\),相当于是要用至多 \(m\) 条长度为 \(k\) 的线段覆盖所有为 \(1\) 的位置,从左往右贪即可。

复杂度 \(O(n \log n)\)

E

首先考虑一个 \(O(n^3)\) 做法。

因为 \(\text{mex}(S)\) 可以被转化为,满足 \([0,k]\) 都在 \(S\) 中出现的 \(k\) 的个数,我们就用这个含义做。

于是考虑枚举区间 \([l,r]\),枚举 \(k\),我们希望求出有多少填数的方案,使得 \([0,k]\) 都在区间 \([l,r]\) 中出现过。

设总共能够填数的位置有 \(t\) 个,区间 \([l,r]\) 中,能够填数的位置有 \(a\) 个,未在 \([0,k]\) 中出现过的数有 \(b\) 个,那么合法填数方案个数为:

\[\binom{a}{b}b!(t-b)! \]

现在我们希望优化到 \(O(n^2)\)

有一个想法是,我们枚举 \([l,r]\) 太憨了,不如去枚举 \(a\)\(b\),然后计算有多少个区间。

但是因为 \(b\)\(k\) 有关,可能不好做,所以我们进行一点转化:设 \(c\) 表示任意的 \(k\),满足 \([0,k-1]\) 都在区间 \([l,r]\) 中出现过,我们计算 \(a,c\) 相同的区间个数,记为 \(f_{a,c}\),那么最终答案为:

\[\sum_{a=0}^n\sum_{c=0}^{n}f_{a,c}(t!c+\sum_{b=1}^{a} \binom{a}{b}b!(t-b)!) \]

最后一项只和 \(a\) 有关,所以可以提前预处理:

\[g_a=\sum_{b=1}^a \binom{a}{b}b!(t-b)! \]

\[\sum_{a=0}^n\sum_{c=0}^{n}f_{a,c}(t!c+g_a) \]

现在考虑 \(f_{a,b}\) 的计算。

还是枚举区间 \([l,r]\),然后记录当前区间的 \(a\) 和最大的 \(c\),每次相当于对 \(f_a\) 做一个 \([0,c]\) 的前缀加,差分即可。

复杂度 \(O(n^2)\)

F

感觉是简单题,但是好像并不简单。

首先考虑什么样的 \(b\) 是合法的,设每个数在 \(a\) 中的出现位置为 \(posa\),在 \(b\) 中的出现位置为 \(posb\),于是 \(b\) 合法,当且仅当对于任意二元组 \((c,d)\),满足 \(c<d,posa_c<posa_d\),都有 \(posb_c<posb_d\)

很好感性理解,因为如果小的数在前面,大的数在后面,那么无论如何它们两个的相对位置不会改变。

于是考虑,对于每一个数,它能够填的位置,一定构成一段区间,所以我们尝试去求出这个区间。做两个二维偏序,用线段树维护,就能求出每个数的合法区间 \(l,r\)

现在的问题转化为,对于每一个数 \(x\),都有一个能够填的区间 \([l_x,r_x]\),询问一个合法填数方案。

我们将区间按 \(l_x\) 升序,\(r_x\) 降序排序,依次填数即可,如果不能满足全部限制即无解。

注意已经填数的位置,我们需要判断它是否在它的合法区间 \([l_x,r_x]\) 里,如果不在即无解。

复杂度 \(O(n \log n)\)

G1

Alice and Bob 能不能消停会。

经过手玩样例,我们得到结论:

\[f(c)=\max(c_1,c_k),k \bmod 2=0 \]

\[f(c)=\min(c_1,c_k),k \bmod 2=1 \]

不会证明,但是根据博弈的过程感觉这就很对。

然后我们把 \(p\) 按下标奇偶分成两个集合,那么集合内部的数是两两取 max,集合外部的数是两两取 min。现在需要填数,满足两个集合的大小分别是 \(cnt_1\)\(cnt_2\),最大化这个值。

于是考虑一个 DP,设 \(f_{i,j}\) 表示填了 \([1,i]\),第一个集合有 \(j\) 个数的最大价值,\(cnt_1,cnt_2\) 分别表示两个集合的大小,转移枚举当前这个数是一集合还是二集合:

\[f_{i,j}=\max(f_{i-1,j-1}+(cnt2-(i-j))i+ji,f_{i-1,j}+(cnt_1-j)i+(i-j)i) \]

注意已经填数的不需要再枚举,直接从对应集合转移就行。

复杂度 \(O(n^2)\)

然后这个做法没有任何优化前途,根本做不了 G2,遗憾离场。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=1e18;
int t,n,c[5005],pos[5005],cnt1,cnt2,f[5005][5005];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>c[i];
            pos[c[i]]=i;
        }
        cnt1=n/2;
        cnt2=n-cnt1;
        for(int i=0;i<=n;i++){
            for(int j=0;j<=cnt1;j++){
                f[i][j]=-inf;
            }
        }
        f[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=i && j<=cnt1;j++){
                if(pos[i]){
                    if(pos[i]&1) f[i][j]=f[i-1][j]+(cnt1-j)*i+(i-j)*i;
                    else if(j) f[i][j]=f[i-1][j-1]+(cnt2-(i-j))*i+j*i;
                }else{
                    if(j) f[i][j]=max(f[i][j],f[i-1][j-1]+(cnt2-(i-j))*i+j*i);
                    f[i][j]=max(f[i][j],f[i-1][j]+(cnt1-j)*i+(i-j)*i);
                }
            }
        }
        cout<<f[n][cnt1]<<'\n';
        for(int i=1;i<=n;i++){
            pos[i]=0;
        }
    }
    return 0;
}
posted @ 2025-04-12 11:46  _Kenma  阅读(10)  评论(0)    收藏  举报