专栏文章

题解:P14636 [NOIP2025] 清仓甩卖 / sale(民间数据)

P14636题解参与者 1已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mimyjlic
此快照首次捕获于
2025/12/01 17:39
3 个月前
此快照最后确认于
2025/12/01 17:39
3 个月前
查看原文
首先对题意进行一下扫盲:
并不是指对于任意定价方案能达到的原价总和最大值。
而是指对于某个给定的定价方案,它利用小 R 的策略买糖果时,能否达到对于这个给定的定价方案的原价总和最大值。
大家一定要好好看样例解释啊!
然鹅我就是因为没看,被hack了十五分钟。
那么我们思考一下,在什么情况下,这个按照性价比降序排序的策略不最优。
看一下下面这个例子:
CPP
m=5
u_i  6 5 10 8 2 
w_i  1 1 2  2 1
我们用 uiu_i 来代替 aia_i
我们模拟一下这个策略,先对 uiwi\frac{u_i}{w_i} 降序排序(已经完成)。
那么首先会购买前三个糖果,然后因为钱不够,不能买第四个糖果,只能跳过这个,最后买第五个糖果。
那么原价为 6+5+10+26+5+10+2
但是我们可以不选第二个和第五个糖果,而购买第四个糖果。
那么原价为 6+10+86+10+8,更加优秀。
这启发我们,这个策略可能在某些情况下买两个 wi=1w_i=1,而这比买一个 wi=2w_i=2 的劣。
观察这个策略买的糖果的位置,可以发现:
买的糖果的区间可以表示为 [1,p]{c}[1,p]\cup\{c\}
究其根本,是因为在买了第 pp 个糖果后,只剩下 11 块钱,被迫放弃后面所有的 wi=2w_i=2 的糖果,最后在后面捞一个 wi=1w_i=1 的糖果,也就是第 cc 个糖果。
记在 [1,p][1,p] 中买得原价最小的 wi=1w_i=1 的糖果下标为 aa[p+1,c1][p+1,c-1] 中原价最大 wi=2w_i=2 的糖果下标为 bb
那么如果 ua+uc<ubu_a+u_c<u_b,那么就可以把糖果 aacc 换成糖果 bb,得到更优的结果。
于是这道题考虑反着做,计算所有使策略不优的定价方案数,也就是存在三元组 (a,b,c)(a,b,c) 的定价方案个数,然后和总可能数 2n2^n 做差就行。
我们将原数组 uu 进行降序排序,以及定义一个新数组 vv 为根据 uiwi\frac{u_i}{w_i} 降序排序的数组。而下文中的 a,b,ca,b,c 表示的是糖果在 uu 的下标,pa,pb,pcp_a,p_b,p_c 表示的是糖果在 vv 的下标。
观察 (a,b,c)(a,b,c) 的性质:
  1. 规定 a<ca<c,则 aa 是倒数第二个买的 wi=1w_i=1 的糖果,而 cc 是最后一个买的糖果,bb 是第一个被跳过的 wi=2w_i=2 的糖果,毕竟是找出一组 ua+uc<ubu_a+u_c<u_b,那么左边的值越小越好,右边的值越大越好。注意 aa 不一定是倒数第二个买的糖果。
  2. a>ba>bpa<pbp_a<p_b,可以理一下:a>ba>b 是因为 ua<ubu_a<u_b,而 pa<pbp_a<p_b 是因为如果 pa>pbp_a>p_b 那么根据 vv 数组的定义,小 R 就不会拿 aa 而是拿 bb 了。
  3. aacc 之间不存在 wi=1w_i=1 的糖果。
  4. ub(ua,2ua)u_b\in (u_a,2u_a)
先考虑枚举 (a,b)(a,b)
现在是让小 R 在买完糖果 aa 和一堆 wi=2w_i=2 的糖果后,仅剩 11 块钱去买糖果 cc
分类讨论 uu 中的下标 ii
  1. i[1,b1]i \in [1,b-1],则 mmwim\gets m-w_i
  2. i[b+1,a1]i \in [b+1,a-1],如果 wi=1w_i=1,则 mm1m\gets m-1;否则 mmm \gets m
  3. i=ai=a,则 mm1m\gets m-1
可以画图理解一下,明白一点:
wi=2w_i=2 的糖果在 vv 中的大小关系,与在 uu 中的大小关系是一致的...
如果实在不明白,再看看性质 11 中关于 bb 的描述吧。
根据上述分讨,可以先让 mm[1,b1]a[1,b-1]\cup {a} 中减一个 11
然后在 [1,b1][b+1,a1][1,b-1]\cup[b+1,a-1] 中选一些位置,让 mm 再减一个 11,使 mm 变到 11。方案数为 Ca2mb1C^{m-b-1}_{a-2}
现在加上 cc,只要使 ua+uc<ubu_a+u_c<u_b 就好,那么考虑从 n1n\rightarrow 1 枚举 uiu_i,找到第一个 ua+uiubu_a+u_i\ge u_b 的位置,则方案数乘上 2ni2^{n-i}。因为在 ii 之后的位置的 wiw_i 可以为 1122,而 ii 之前的位置的 wiw_i 只能为 22,由 (a,b,c)(a,b,c) 的性质 1133 可得。
bba11a-1\rightarrow 1 枚举,发现 ubu_b 单调不降,则用一个双指针维护 cc 就可以了。
则将 uu 数组降序排序后,最终答案为: ans=2nr=1nl=1r1Cr2ml1×2nk,ul(ur,2ur)ans=2^n-\sum_{r=1}^{n} \sum_{l=1}^{r-1}C_{r-2}^{m-l-1}\times 2^{n-k},u_l \in (u_r,2u_r) 其中,kk 表示满足 ulur+uku_l \le u_r+u_k 的最大下标。
预处理 22 的幂次和组合数后,时间复杂度为 O(n2)O(n^2)
代码如下:
CPP
#include <iostream>
#include <algorithm>
#define maxn 5005
#define int long long
#define mod 998244353
using namespace std;
int c,t,n,m,a[maxn],qw2[maxn],fac[maxn],inv[maxn];
int C(int n,int m){
    if(n<0||m<0||n<m) return 0;
    return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
signed main(){
    qw2[0]=fac[0]=fac[1]=inv[0]=inv[1]=1;
    for(int i=1;i<=maxn-5;i++) qw2[i]=qw2[i-1]*2%mod;
    for(int i=2;i<=maxn-5;i++) fac[i]=fac[i-1]*i%mod;
    for(int i=2;i<=maxn-5;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<=maxn-5;i++) inv[i]=inv[i-1]*inv[i]%mod;
    cin>>c>>t;
    while(t--){
        int ans=0;
        cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+n+1),reverse(a+1,a+n+1);
        for(int r=1;r<=n;r++){
            int k=n;
            for(int l=r-1;l>=1;l--){
                if(a[r]<a[l]&&a[l]<a[r]*2){
                    while(a[l]>a[r]+a[k]) k--;
                    ans=(ans+C(r-2,m-l-1)*qw2[n-k])%mod;
                }
            }
        }
        cout<<(qw2[n]-ans+mod)%mod<<"\n";
    }
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...