专栏文章
P14636 题解
P14636题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mimx4k6a
- 此快照首次捕获于
- 2025/12/01 16:59 3 个月前
- 此快照最后确认于
- 2025/12/01 16:59 3 个月前
补题一小时过了,没有学题解的任何东西,因为我看不懂。
考虑原价不取到最大值的情况。如果一个物品可以取到肯定是最优的,因为性价比从大到小排序。但是如果一个物品没钱买可能就会出现问题。
考虑一种情况:按性价比从大到小选,到一个 的物品 ,刚好剩余一块钱, 之前最近选了一个 的物品 , 之后有一个物品 满足 且 。物品的性价比从大到小为 。
按照小 R 的贪心思路,她会先选择 。接下来 由于需要两块钱,但是只有一块钱没法选,所以小 R 会去选择 并把钱花完。但是由于 ,用 替换 更优,就会导致贪心出错。
既然是由 引起的贪心出错,那么我们枚举他们三个。注意 可能没有,可以认为 。
考虑 这四个区间内的 应如何选择。

之间物品的权值是不确定的。因此枚举这个区间内 的个数,设为 。方案数为 。
上面这行文字是我赛时没有想到的,赛时以为 之间全是 ,
sale2.in 调了一辈子,宝宝我真糖。好在想错了还有 的 分保底。接着对于 之间的物品,还需要花 元( 性价比比 高,会先选择并花费 元)。即在 个物品中,每个物品有 的权值,问凑出 的方案数。给权值 ,变成 中选择 个 ,答案为 。
其他的在图中已经说清楚了,直接按照前文模拟,时间复杂度 ,可以斩获比暴力多过一个测试点 的好成绩。
code
CPPans=Pow(2,n);
for(int k=2;k<=n;k++)
{
for(int i=1;i<k;i++)
{
if(a[i]*2<=a[k]||m-(n-k)<1) continue;
for(int j=0;j<i;j++)
{
if(a[i]+a[j]>=a[k]) continue;
for(int x=0;x<=k-i-1&&m-(n-k)-x>=2;x++)
{
if(m-(n-k)*2-x>2) continue;
ans=(ans-Pow(2,j-1)*C[n-k][m-x-2-(n-k)]*C[k-i-1][x])%mod;
}
}
}
}
枚举条件可以不用的,因为不合法的话组合数为 。
发现 其实是没用的,唯一用处在于 。双指针一下就可以去掉 的枚举,做到 ,理论上 ,实测 。
考虑去掉 的枚举。如果你打了上周 ABC,会发现 F 题恰好有这个结论。引用一下原题第一篇题解的 Markdown。
范德蒙德卷积
证明:考虑一共有 个物品,从中选 个。这件事情等价于在 个物品中先选 个,再在剩下 个物品中选 个。改变的仅仅是枚举顺序。
代入到 的代码中,就是:
ans=(ans-sum*C[n-j-1][m-2-(n-k)])%mod;于是就可以做到 。
code
CPP#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define N 5005
using namespace std;
int sub,n,m,ans,a[N],C[N][N];
int Pow(int x,int y)
{
if(y<0) return 0;
int res=1;
while(y)
{
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
ans=Pow(2,n);
for(int k=2;k<=n;k++)
{
int p=0,sum=1;
for(int j=k-1;j>=1;j--)
{
while(p<n&&a[p+1]<a[k]-a[j]) p++,sum=sum*2%mod;
if(a[j]*2<=a[k]||m-(n-k)<1||a[j]==a[k]) continue;
if(m-2-(n-k)>=0&&m-2-(n-k)<=n-j-1) ans=(ans-sum*C[n-j-1][m-2-(n-k)])%mod;
}
}
ans=(ans+mod)%mod;
cout<<ans<<"\n";
return;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
C[0][0]=1;
for(int i=1;i<=5000;i++)
{
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
int t;
cin>>sub>>t;
while(t--) solve();
return 0;
}
事实上我的赛时:T2 调了三小时,操你妈的世界。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...