[P14636] [NOIP2025] 清仓甩卖 / sale 题解
aeiouaoeiu · · 题解
赛时花费
设确定
观察一个不合法的情况,形如取了一个前缀到
然后一个自然的想法是,枚举
这个
首先可以钦定,
需要计算的方案数可以分成三部分:
先考虑
直接枚举满足
注意到对于一对
upd:赛时代码最终在 CCF 机子上通过,但是并不能在洛谷上通过。以下是经过略微卡常后在洛谷上通过的代码,最后两个点均小于
:::info[code]
#include<bits/stdc++.h>
#define pb emplace_back
#define mp make_pair
#define pob pop_back
using namespace std;
typedef long long ll;
const ll maxn=100007,p=998244353;
ll n,m,cid,a[maxn],b[maxn],id[maxn],c[2][maxn],pw[maxn],ans;
ll frac[maxn],inv[maxn],s3[maxn],rev[maxn],to[maxn],nxt[maxn];
vector<pair<ll,ll> > vec;
void ups(ll &a,ll b){a=(a+b>=p)?(a+b-p):(a+b);}
void mul(ll &a,ll b){a=(a<b)?(a+p-b):(a-b);}
ll qpow(ll a,ll b){ll E=1; for(;b;b>>=1,a=a*a%p)if(b&1) E=E*a%p; return E;}
void init(void){
pw[0]=frac[0]=1;
for(ll i=1;i<maxn;i++) pw[i]=pw[i-1]*2%p,frac[i]=frac[i-1]*i%p;
inv[maxn-1]=qpow(frac[maxn-1],p-2);
for(ll i=maxn-1;i>=1;i--) inv[i-1]=inv[i]*i%p;
}
ll C(ll a,ll b){return (a<b||b<0)?0:frac[a]*inv[b]%p*inv[a-b]%p;}
ll solve(void){
ans=0;
for(ll i=1;i<=n;i++) b[2*i-1]=a[i],b[2*i]=2*a[i];
for(ll i=1;i<=2*n;i++) id[i]=i;
sort(id+1,id+1+2*n,[&](ll x,ll y){
if(b[x]==b[y]){
if((x&1)==(y&1)) return x<y;
else return (bool)(x&1);
}
return b[x]>b[y];
});
for(ll i=1;i<=2*n;i++){
c[0][i]=c[0][i-1],c[1][i]=c[1][i-1];
c[id[i]&1][i]++;
rev[id[i]]=i;
}
for(ll y=1;y<=2*n;y++){
s3[y]=s3[y-1];
if(id[y]%2==0) ups(s3[y],pw[c[0][2*n]-c[0][y]]);
}
vec.clear();
for(ll i=1,lst=-1;i<=2*n;i++){
if(id[i]%2==0) lst=vec.size(),vec.pb(i,id[i]);
to[i]=lst;
}
for(ll i=2*n,lst=n;i>=1;i--){
nxt[i]=lst;
if(id[i]%2==0) lst--;
}
vec.pb(2*n+1,2*n);
for(ll z=1,iz,cur,s2;z<=2*n;z++){
if(id[z]%2==0) continue;
iz=id[z];
for(ll tx=to[z],x,ix,bx,cy=nxt[z];tx;tx--){
x=vec[tx].first,ix=vec[tx].second,bx=b[ix];
if((ix+1)/2==(iz+1)/2) continue;
if(bx>=2*b[iz]) break;
for(;cy<n&&b[vec[cy].second]+bx>=2*b[iz];cy++);
cur=C(c[0][x-1]-1,m-2-c[1][z-1]);
s2=s3[2*n],mul(s2,s3[vec[cy].first-1]);
ups(ans,cur*(s2+1)%p);
}
}
return (pw[n]-ans+p)%p;
}
int main(void){
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0);
ll T=1; cin>>cid>>T;
init();
for(;T--;){
cin>>n>>m;
for(ll i=1;i<=n;i++) cin>>a[i];
cout<<solve()<<"\n";
}
return 0;
}
:::