题面简述
定义两个数列\(S = \{S(1), S(2), ..., S(n)\}\)和\(S_2 = \{S_2(1), S_2(2), ..., S_2(n)\}\),
\[S(k) = (p_k\times k) \bmod w,\text{where } p_k \text{ is the kth prime number}\]
\[S_2(k) = S(k) + S(\lfloor\frac{k}{10}\rfloor + 1)\]
令\(M(i,j)\)表示\(S_2(i)\)到\(S_2(j)\)的中位数。现在给定\(n,k\)求
\[\sum_{i=1}^{n-k+1} M(i, i + k - 1)\]
\(w\leq k\leq n \leq 10^7\)
col
我们先用线性筛筛出素数,然后就可以构造出\(S1\)和\(S2\)了,我们发现S2数组没什么规律,也就是说可以看做是随机构造的。在一个滑动窗口中随机构造的数的中位数变化很小,于是我们可以用两个指针控制住中位数,就可以求解了。因为数的范围很小,我们就可以用计数的方法来找中位数。
code
#include<bits/stdc++.h>
using namespace std;
int n,k,w,len,P[maxn],S[maxn],S2[maxn],cnt[maxn*2],p1=-1,p2=-1,cur1,cur2;bool vis[179424678];double ans;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline void make_p(){
for(int i=2;;i+=(i&1)+1){
if(!vis[i]){P[++plen]=i;if(plen==n) break;}
for(int j=1;j<=plen&&i*P[j]<=179424673;j++){
vis[i*P[j]]=true;
if(i%P[j]==0) break;
}
}
}
int main(){
n=read();k=read();w=read();
make_p();
for(int i=1;i<=n;i++) S[i]=(long long)P[i]*i%w;
for(int i=1;i<=n;i++)S2[i]=S[i]+S[i/10+1];
for(int i=1;i<=k;i++) cnt[S2[i]]++;
for(int i=1;i<=n-k+1;i++)
{
while(cur1<k/2) cur1+=cnt[++p1];
while(cur1-cnt[p1]>=k/2) cur1-=cnt[p1--];
while(cur2<k/2+1) cur2+=cnt[++p2];
while(cur2-cnt[p2]>=k/2+1) cur2-=cnt[p2--];
if(k&1) ans+=p2;
else ans+=p1+p2;
if(i<n-k+1){
cnt[S2[i]]--;
if(S2[i]<=p1) cur1--;
if(S2[i]<=p2) cur2--;
cnt[S2[k+i]]++;
if(S2[k+i]<=p1) cur1++;
if(S2[k+i]<=p2) cur2++;
}
}
printf("%.1lf",k&1?ans:ans/2);
return 0;
}