专栏文章

P14636 [NOIP2025] 清仓甩卖

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

文章操作

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

当前评论
0 条
当前快照
1 份
快照标识符
@min098xv
此快照首次捕获于
2025/12/01 18:27
3 个月前
此快照最后确认于
2025/12/01 18:27
3 个月前
查看原文
过了所有大样例和洛谷数据。虽然 4h 才切,但也算是一雪前耻了。
前置知识
上一场 ABC 不是白打的。
Hint
正难则反,取不到最大原价总和只有两种情况:
  • 最优解选性价比较低的 22,小 R 选性价比较高的 11
  • 最优解选性价比中的 22,小 R 选性价比较高的 11 和性价比较低的 11,且两个 11 的原价之和低于 22 的原价。
显然上述的 22 是最优解中选取的性价比最低的 22,上述的 11 是小 R 选取的性价比最低的 11
按原价从大到小排序,枚举:
  • 对于第一种情况,枚举最优解的 22(记为 ii)以及小 R 的 11(记为 jj),则 ai>aj>12aia_i>a_j>\frac{1}{2}a_i,而所有 k>jk>j 必有 wk=2w_k=2,枚举 uu1i11\sim i-122 的数量,则方案数为:
u=0i1(i1u)(ji1m(i1)u2)=(j2mi1)\sum_{u=0}^{i-1}\dbinom{i-1}{u}\dbinom{j-i-1}{m-(i-1)-u-2}=\dbinom{j-2}{m-i-1}
  • 对于第二种情况,枚举最优解的 22(记为 ii)以及小 R 的较高的 11(记为 jj),则 ai>aj>12aia_i>a_j>\frac{1}{2}a_i,设 pp 为使得 ak+aj<aia_k+a_{j}< a_{i} 的最小下标 kk,枚举 uu1i11\sim i-122 的数量,则方案数为:
2np+1u=0i1(i1u)(ji1m(i1)u2)=2np+1(j2mi1)2^{n-p+1}\cdot\sum_{u=0}^{i-1}\dbinom{i-1}{u}\dbinom{j-i-1}{m-(i-1)-u-2}=2^{n-p+1}\cdot\dbinom{j-2}{m-i-1}
时间复杂度 O(n2)\mathcal{O}(\sum n^2),空间复杂度 O(n2)\mathcal{O}(n^2)O(n)\mathcal{O}(n)
[NOIP2025] 清仓甩卖 - sale.cppCPP
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
const int mod=998244353;
int dp[maxn][maxn],pre[maxn],a[maxn];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    dp[0][0]=pre[0]=1;
    for(int i=1;i<=maxn-10;i++){
        dp[i][0]=1;
        pre[i]=pre[i-1]<<1;
        if(pre[i]>=mod) pre[i]-=mod;
        for(int j=1;j<=i;j++){
            dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
            if(dp[i][j]>=mod) dp[i][j]-=mod;
        }
    }
    int c,t;cin>>c>>t;
    while(t--){
        int n,m;cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n,greater<int>());
        long long ans=0;
        for(int i=1;i<=n;i++){
            if(m-i-1<0) break;
            int p=n+1;
            for(int j=max(i+1,m-i+1);j<=n;j++){
                if(a[i]==a[j]) continue;
                if(a[i]>=(a[j]<<1)) break;
                while(p>1 and a[p-1]+a[j]<a[i]) p--;
                ans+=1ll*dp[j-2][m-i-1]*pre[n-p+1]%mod;
            }
        }
        cout<<(pre[n]-ans%mod+mod)%mod<<"\n";
    }
    return 0;
}

评论

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

正在加载评论...