定义两个数列: S={S1,S2……Sn} S = { S 1 , S 2 … … S n } , S2={S21,S22,……S2n} S 2 = { S 2 1 , S 2 2 , … … S 2 n }
其中
Si=(Pi∗i)mod W S i = ( P i ∗ i ) m o d W ( Pi P i 表示第 i i 个素数)
S2i=Si+S⌊i/10⌋+1 S 2 i = S i + S ⌊ i / 10 ⌋ + 1
求
∑n−k+1i=1M(i,i+k−1) ∑ i = 1 n − k + 1 M ( i , i + k − 1 ) ( M(L,R) M ( L , R ) 表示 S2[L,R] S 2 [ L , R ] 的中位数)
n,k,W<=10000000,2s n , k , W <= 10000000 , 2 s
首先,筛出第 10000000 10000000 个素数?素数的分布是近似 log l o g 的,所以第 10000000 10000000 个素数应近似为 200000000 200000000 (实际为 179424673 179424673 ),此时 log l o g 级的筛素数都吃不消了,只能上高端线性欧拉筛+各种卡常:(然而还是要 1.5s 1.5 s !!!)
void make(){
for(__R int i=2;i<=N;i+=(i&1)+1){
if(!vis[i]){p[++p[0]]=i;if(p[0]==n) return;}
for(__R int j=1;j<=p[0];j++){
if(p[j]>N/i) break;
vis[p[j]*i]=1;
if(!(i%p[j])) break;
}
}
}
然后, O(1) O ( 1 ) 求区间中位数?
log l o g 的做法有很多,写大小两个堆或直接上平衡树,但 0.5s 0.5 s 你想干嘛。。
然后玄学的来了。。
注意到这题的输入很诡异,其实可以当做是随机数据 那么随机数据满足分布均匀,也就是说可以假定,中位数的值变化也是常数级的
那么只要维护一个指针,挪动更新下中位数的位置就好了 ——摘自 Solution S o l u t i o n
每次区间移动只更改两个元素,看起来也挺有道理的吧QWQ
然后就是写起来太像玄学的莫队了。。
#pragma GCC optimize(2)
#include
#include
#define __R register
#define LL long long
using namespace std;
const int maxp=(1e7)+5,maxn=179424680,N=179424673;
int n,k,TT,p[maxp],C[maxp],A[maxp],hsh[maxp<<1];bool vis[maxn];LL Ans;
int Q;
void make(){
for(__R int i=2;i<=N;i+=(i&1)+1){
if(!vis[i]){p[++p[0]]=i;if(p[0]==n) return;}
for(__R int j=1;j<=p[0];j++){
if(p[j]>N/i) break;
vis[p[j]*i]=1;
if(!(i%p[j])) break;
}
}
}
int main(){
scanf("%d%d%d",&n,&k,&TT),make();
for(__R int i=1;i<=n;i++) C[i]=(LL)p[i]*i%TT,A[i]=C[i]+C[i/10+1];
for(__R int i=1;iint b1=-1,b2=-1,lst1=0,lst2=0,kk=k+1>>1;bool flg=(k&1);
for(__R int i=k;i<=n;i++){
hsh[A[i]]++,lst1+=(A[i]<=b1),lst2+=(A[i]<=b2);
if(i>k) hsh[A[i-k]]--,lst1-=(A[i-k]<=b1),lst2-=(A[i-k]<=b2);
while(lst1while(lst21) lst2+=hsh[++b2];
while(lst1-hsh[b1]>=kk) lst1-=hsh[b1--];
while(lst2-hsh[b2]>=kk+1) lst2-=hsh[b2--];
if(flg) Ans+=b1+b1;else Ans+=b1+b2;
}
if(Ans&1) printf("%lld.5\n",Ans>>1);else printf("%lld.0\n",Ans>>1);
return 0;
}