20210628模拟赛
数学场,体验感极好(捕获一只热爱数学的yxy
这是到目前为止除了 ASDFZ 的第一套以外考过的最难的一套模拟了
然后发现是我母亲的母校出的题 CDQZ yyds
T1 数论,T2 生成函数,T3 计数
感觉补完题后最有收获的是 T2,好好分析一波
好题
分析 :
形式化的答案就是
∑
b
(
b
+
c
)
≤
n
2
,
c
≤
3
b
[
b
(
b
+
c
)
∈
N
]
b
(
b
+
c
)
\sum_{b(b+c)\le n^2,c\le 3b}[\sqrt{b(b+c)}\in N]\sqrt{b(b+c)}
b(b+c)≤n2,c≤3b∑[b(b+c)∈N]b(b+c)
考虑
g
c
d
(
b
,
c
)
=
1
gcd(b,c)=1
gcd(b,c)=1 的情况,此时
b
b
b 一定是一个平方数,于是令
b
=
x
2
,
a
=
x
y
,
c
=
y
2
−
x
2
b=x^2,a=xy,c=y^2-x^2
b=x2,a=xy,c=y2−x2
代入不等式得到 y 2 − x 2 < 3 x 2 → y < 2 x y^2-x^2<3x^2 \to y<2x y2−x2<3x2→y<2x
所以
g
c
d
(
b
,
c
)
=
1
gcd(b,c)=1
gcd(b,c)=1 的答案就是
∑
x
y
≤
n
,
g
c
d
(
x
,
y
)
=
1
,
x
<
y
<
2
x
x
y
\sum_{xy\le n,gcd(x,y)=1,x<y<2x} xy
xy≤n,gcd(x,y)=1,x<y<2x∑xy
如果
g
c
d
(
b
,
c
)
≠
1
gcd(b,c)\ne 1
gcd(b,c)=1 ,可以把
b
,
c
b,c
b,c 化成互质,然后答案
×
g
c
d
(
a
,
b
)
\times gcd(a,b)
×gcd(a,b) ,令
S
(
x
)
=
∑
i
=
1
x
i
S(x)=\sum_{i=1}^xi
S(x)=∑i=1xi
那么总的答案就是
∑
x
y
≤
n
,
g
c
d
(
x
,
y
)
=
1
,
x
<
y
<
2
x
x
y
S
(
n
/
x
y
)
\sum_{xy\le n,gcd(x,y)=1,x<y<2x} xyS(n/xy)
xy≤n,gcd(x,y)=1,x<y<2x∑xyS(n/xy)
看着这个
g
c
d
gcd
gcd 就很烦,所以把它反演掉
∑
t
μ
(
t
)
∑
x
y
≤
n
/
t
2
,
x
<
y
<
2
x
x
y
t
2
S
(
n
/
t
2
x
y
)
\sum_t\mu(t)\sum_{xy\le n/t^2,x<y<2x} xyt^2S(n/t^2xy)
t∑μ(t)xy≤n/t2,x<y<2x∑xyt2S(n/t2xy)
这个式子可以整除分块,具体来说,第一维对
t
t
t 整除分块,然后枚举
x
x
x ,最后对
y
y
y 整除分块。可以做到
O
(
n
2
/
3
)
O(n^{2/3})
O(n2/3)。感性理解一下复杂度,
t
t
t 变大一点点后面的
x
,
y
x,y
x,y 的范围就会大幅度变小,所以远远跑不到
O
(
n
)
O(n)
O(n) 的。
#include <bits/stdc++.h>
#define N 1000006
using namespace std;
typedef unsigned long long ll;
ll pri[N],num,u[N],sum[N];
bool tag[N];
void init(){
u[1]=sum[1]=1;
ll a,n=1e6;
for(int i=2;i<=n;sum[i]=sum[i-1]+u[i]*i*i,i++){
if(!tag[i]) pri[++num]=i,u[i]=-1;
for(int j=1;j<=num&&(a=i*pri[j])<=n;j++){
tag[a]=1,u[a]=-u[i];
if(i%pri[j]==0){ u[a]=0; break; }
}
}
}
int main(){
init();
ll n,sqr,res=0,now,lim_x,lim_y,z,S;
cin>>n; sqr=sqrt(n);
for(ll t=1,tr;t<=sqr;t=tr+1){
tr=min((ll)sqrt(n/(n/(t*t))),sqr);
lim_x=n/(t*t);
for(ll x=1;x<=lim_x/(x+1);x++){
now=(sum[tr]-sum[t-1])*x;
lim_y=min(lim_x/x,x+x-1);
z=n/t/t/x;
for(ll y=x+1,yr;y<=lim_y;y=yr+1){
yr=min(z/(z/y),lim_y);
S=(z/y)*(z/y+1)/2;
if((y+yr)&1) res+=(yr-y+1)/2*(y+yr)*now*S;
else res+=(y+yr)/2*(yr-y+1)*now*S;
}
}
}
cout<<res<<endl;
}
考虑答案的生成函数
F
(
x
)
=
x
F
(
x
)
+
F
(
x
k
)
∑
i
=
0
k
−
1
x
i
F(x)=xF(x)+F(x^k)\sum_{i=0}^{k-1} x^i
F(x)=xF(x)+F(xk)i=0∑k−1xi
化简一下
F
(
x
)
=
x
F
(
x
)
+
F
(
x
)
(
1
1
−
x
−
x
k
1
−
x
)
(
1
−
x
)
F
(
x
)
=
(
1
−
x
k
)
F
(
x
k
)
1
−
x
F(x)=xF(x)+F(x)(\frac{1}{1-x}-\frac{x^k}{1-x})\\ (1-x)F(x)=\frac{(1-x^k)F(x^k)}{1-x}
F(x)=xF(x)+F(x)(1−x1−1−xxk)(1−x)F(x)=1−x(1−xk)F(xk)
发现两边的格式是一样的,考虑一直展开下去
F
(
x
)
=
1
(
1
−
x
)
∏
i
≥
0
1
−
x
k
i
F(x)=\frac{1}{(1-x)\prod_{i\ge 0} 1-x^{k^i}}
F(x)=(1−x)∏i≥01−xki1
然后把
1
1
−
x
\frac{1}{1-x}
1−x1 这样展开
1
1
−
x
=
∑
j
≥
0
x
j
=
(
1
+
x
+
x
2
+
.
.
.
+
x
k
−
1
)
(
1
+
x
k
+
x
2
k
+
.
.
.
x
(
k
−
1
)
k
)
.
.
.
1
1
−
x
k
i
=
(
1
+
x
k
i
+
x
2
k
i
+
.
.
.
+
x
(
k
−
1
)
k
i
)
(
1
+
x
k
i
+
1
+
x
2
k
i
+
1
+
.
.
.
x
(
k
−
1
)
k
i
+
1
)
.
.
.
\frac{1}{1-x}=\sum_{j\ge 0} x^j=(1+x+x^2+...+x^{k-1})(1+x^k+x^{2k}+...x^{(k-1)k})...\\ \frac{1}{1-x^{k^i}}=(1+{x^{k^{i}}}+x^{2k^{i}}+...+x^{(k-1)k^{i}})(1+x^{k^{i+1}}+x^{2k^{i+1}}+...x^{(k-1)k^{i+1}})...
1−x1=j≥0∑xj=(1+x+x2+...+xk−1)(1+xk+x2k+...x(k−1)k)...1−xki1=(1+xki+x2ki+...+x(k−1)ki)(1+xki+1+x2ki+1+...x(k−1)ki+1)...
代入
F
(
x
)
F(x)
F(x) 得到
F
(
x
)
=
∏
i
≥
0
(
∑
j
=
0
k
−
1
x
j
k
i
)
i
+
2
F(x)=\prod_{i\ge 0}(\sum_{j=0}^{k-1}x^{jk^i})^{i+2}
F(x)=i≥0∏(j=0∑k−1xjki)i+2
我们要求的答案是
[
x
n
]
F
(
x
)
[x^n]F(x)
[xn]F(x) ,观察上面这个式子可以发现
∏
i
≥
1
(
∑
j
=
0
k
−
1
x
j
k
i
)
i
+
2
≡
0
m
o
d
x
k
\prod_{i\ge 1}(\sum_{j=0}^{k-1}x^{jk^i})^{i+2}\equiv0 \mod{x^k}
∏i≥1(∑j=0k−1xjki)i+2≡0modxk ,所以
n
m
o
d
k
n\mod{k}
nmodk 的部分是由
(
∑
j
=
0
k
−
1
x
j
)
2
(\sum_{j=0}^{k-1}x^j)^2
(∑j=0k−1xj)2 中的某一项系数组成的。
题解举了个例子
所以每次只保留 ( ∑ j = 0 k − 1 x j ) 2 (\sum_{j=0}^{k-1}x^j)^2 (∑j=0k−1xj)2 中次数 ≡ n m o d k \equiv n\ mod\ k ≡n mod k 的项,然后对整体开 k k k 次根。然后把前面的多项式乘以后面 ∏ \prod ∏ 中 i = 0 i=0 i=0 的部分,重复这个过程,就能得到答案。
#include <bits/stdc++.h>
#define N 502
using namespace std;
typedef long long ll;
typedef vector<ll> vec;
const int mod=1e9+7;
int n,k,a[N];
vec now,o,A;
vec mul(const vec &x,const vec &y,int lim){
vec res; int len=x.size()+y.size()-1;
ll tmp=0;
for(int i=lim;i<len;i+=k){
tmp=0;
for(int j=max(0,i-(int)y.size()+1);j<x.size()&&j<=i;j++)
tmp+=x[j]*y[i-j]%mod;
res.push_back(tmp%mod);
}
return res;
}
void to_nxt(){
now.resize(now.size()+k-1);
for(int i=1;i<now.size();i++) now[i]=now[i]+now[i-1],now[i]=(now[i]<mod?now[i]:now[i]-mod);
for(int i=now.size()-1;i>=k;i--) now[i]=now[i]-now[i-k]+mod,now[i]=(now[i]<mod?now[i]:now[i]-mod);
}
void solve(int d){
A=mul(A,now,a[d]);
to_nxt();
if(d==n-1) return;
solve(d+1);
}
int main(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
cin>>k;
for(int i=0;i<k;i++) now.push_back(1);
A.push_back(1);
to_nxt();
solve(0);
cout<<A[0]<<endl;
}
注意到题目保证数据随机,我们可以利用这一点来作文章。 有一个为人所熟知的结论,即设 h ( l , r ) = max l ≤ x ≤ r a l ⊗ a x h(l, r) = \max_{l≤x≤r} a_l ⊗ a_x h(l,r)=maxl≤x≤ral⊗ax,在 a a a 随机的情况下,固定左 端点 l l l 不动,所有不同的 h ( l , r ) h(l, r) h(l,r) 数量的期望为 O ( l n n ) O(ln n) O(lnn) ( r ∈ [ 1 , n ] r ∈ [1, n] r∈[1,n])。 考虑推广这一结论,我们可以大胆猜测,在 a a a 随机的情况下,固定左端点 l l l,所有不同 的 g ( l , r ) g(l, r) g(l,r) 数量的期望为 O ( l n n ) O(ln_n) O(lnn) 。
然后你发现你猜对了。
(想到这里后面就很自然了,不赘述了。
#include <bits/stdc++.h>
using namespace std;
namespace iobuff{
const int LEN=1000000;
char in[LEN+5],out[LEN+5];
char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
inline char gc(void){
return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;
}
inline void pc(char c){
pout==eout&&(fwrite(out,1,LEN,stdout),pout=out);
(*pout++)=c;
}
inline void flush(){fwrite(out,1,pout-out,stdout),pout=out;}
template<typename T> inline void read(T &x){
static int f;
static char c;
c=gc(),f=1,x=0;
while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
x*=f;
}
template<typename T> inline void putint(T x,char div){
static char s[15];
static int top;
top=0;
x<0?pc('-'),x=-x:0;
while(x) s[top++]=x%10,x/=10;
!top?pc('0'),0:0;
while(top--) pc(s[top]+'0');
pc(div);
}
}
using namespace iobuff;
const int N=1e5+5,Q=1e6+5;
#define ll long long
int n,m,q;
namespace Trie{
int ch[N<<5][2],sz[N<<5],mx[N<<5],inde=1;
inline void insert(int x,int pos){
int u=1;++sz[u];
for(int i=m,v;~i;--i){
v=(x>>i)&1;
if(!ch[u][v])ch[u][v]=++inde,mx[inde]=pos;
else mx[ch[u][v]]=pos;
u=ch[u][v];++sz[u];
}
}
int tot;
inline void query(int u,int L,int x,int dep,int *ans){
if(!u||!sz[u]||mx[u]<L)return;
if(dep<0){ans[++tot]=mx[u];return;}
int v=x>>dep&1,l=ch[u][v],r=ch[u][v^1];
if(!l||!r){query(l^r,L,x,dep-1,ans);return;}
if(mx[r]>mx[l]){query(r,L,x,dep-1,ans);return;}
else{
query(l,max(L,mx[r]),x,dep-1,ans);
if(L<mx[r])query(r,L,x,dep-1,ans);
}
}
}
namespace BIT{
ll t1[N],t2[N];
void modify(int l,int r,ll v){
if(l>r)return;
for(int x=l;x<=n;x+=(x&-x)) t1[x]+=v,t2[x]+=v*l;
for(int x=r+1;x<=n;x+=(x&-x)) t1[x]-=v,t2[x]-=v*(r+1);
}
ll query(int x){
ll ret=0;
for(int i=x;i;i-=(i&-i)) ret+=t1[i]*(x+1)-t2[i];
return ret;
}
}
int pos[N],val[N],tot,mxpos[N],mxval[N],mxtot,buc1[N],buc2[N],curtot;
ll sum;
inline void merge(){
curtot=0;
int j=1;
for(int i=1;i<=mxtot;++i){
while(j<=tot&&pos[j]>=mxpos[i]){
buc1[++curtot]=pos[j];
buc2[curtot]=val[j++];
}
buc1[++curtot]=mxpos[i];
buc2[curtot]=mxval[i];
}
while(j<=tot){
buc1[++curtot]=pos[j];
buc2[curtot]=val[j++];
}
mxtot=0;
for(int i=1;i<=curtot;++i){
if(buc2[i]<=mxval[mxtot])continue;
if(mxpos[mxtot]==buc1[i])--mxtot;
mxval[++mxtot]=buc2[i];
mxpos[mxtot]=buc1[i];
}
mxpos[mxtot+1]=0;
for(int i=1;i<=mxtot;++i){
sum+=1ll*mxval[i]*(mxpos[i]-mxpos[i+1]);
BIT::modify(mxpos[i+1]+1,mxpos[i],mxval[i]);
}
}
int x[N],tp;
struct Query{int l,r,id;}query[Q];
inline bool operator <(Query a1,Query a2){return a1.r<a2.r;}
ll ans[Q];
inline void read(int n,int m,unsigned int seed,int tp){
mt19937 rnd(seed);
for(int i=1;i<=n;++i){
if(tp==4) x[i]=1<<(rnd()%m);
else x[i]=rnd()&((1<<m)-1);
}
}
unsigned int seed;
int main(){
read(n);read(m);read(q);read(tp);
read(seed);
read(n,m,seed,tp);--m;
for(int i=1;i<=q;++i){read(query[i].l);read(query[i].r);query[i].id=i;}
sort(query+1,query+1+q);
int flag=1;ll ret=0;
tp=(q>=100000);
for(int i=1;i<=n&&flag<=q;++i){
Trie::tot=0;
Trie::query(1,0,x[i],m,pos);
tot=Trie::tot;
for(int j=1;j<=tot;++j)val[j]=x[i]^x[pos[j]];
Trie::insert(x[i],i);
merge();
while(flag<=q&&query[flag].r==i){
ans[query[flag].id]=sum-BIT::query(query[flag].l-1);
ans[query[flag].id]=sum-BIT::query(query[flag].l-1);
if(tp)ret^=ans[query[flag].id];++flag;
}
}
if(tp){
putint(ret,'\n');flush();return 0;
}
for(int i=1;i<=q;++i)putint(ans[i],'\n');flush();
return 0;
}