解题思路
对于每一个数 ,我们可以分情况讨论:
情况一: 不翻倍
若 不翻倍,我们可以发现 到 都是不能翻倍的,否则就会改变 的排名。
设这个范围内有 个数,则有 种方案。
情况二: 翻倍
若 翻倍,我们同样可以发现 到 都是要跟着翻倍的,否则也会改变 的排名。
设这个范围内的数有 个,则有 种方案。
我们可以用二分找出 和 的位置,算出对应的 。
特殊情况:
注意,如果 为 ,则方案数应该为 。
如果有重复的 ,要以第一个 的位置算。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int mod=998244353;
struct node{
int num,id;
}a[100001];
int f[100001],g[100001];
int ans[100001];
map<int,int> fir;
bool cmp(node x,node y)
{
return x.num<y.num;
}
int c(int n,int m)
{
if(m>n)return 0;
return f[n]*g[m]%mod*g[n-m]%mod;
}
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
{
res*=a;
res%=mod;
}
b>>=1;
a*=a;
a%=mod;
}
return res;
}
int erfen(int x)
{
int l=1,r=n;
int mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(a[mid].num<=x)
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
return ans;
}
main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>k;
f[0]=g[0]=1;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]*i%mod;
g[i]=g[i-1]*qpow(i,mod-2)%mod;
f[i]=(f[i]+mod)%mod;
g[i]=(g[i]+mod)%mod;
}
for(int i=1;i<=n;i++)
{
cin>>a[i].num;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(fir.count(a[i].num)==0)
{
fir[a[i].num]=i;
}
}
int x,wz;
for(int i=1;i<=n;i++)
{
if(a[i].num==0)
{
ans[a[i].id]=(c(n,k)+mod)%mod;
continue;
}
if(a[i].num%2==0)
wz=erfen(a[i].num/2-1);
else
wz=erfen(a[i].num/2);
x=n-(fir[a[i].num]-wz);
ans[a[i].id]+=(c(x,k)+mod)%mod;
wz=erfen(a[i].num*2-1);
x=wz-fir[a[i].num]+1;
if(k>=x)
{
ans[a[i].id]+=(c(n-x,k-x)+mod)%mod;
ans[a[i].id]=(ans[a[i].id]+mod)%mod;
}
}
for(int i=1;i<=n;i++)
{
cout<<(ans[i]+mod)%mod<<endl;
}
}