考试经历
先看了一眼第一题,手玩了几个小数据,没发现什么规律,先跳了,0.5h
第二题感觉
80
p
t
s
80pts
80pts 暴力白送,想了一会儿正解没想出来,不想了,代码很短,码完 1h
第三题对异或的平方和感觉毫无头绪,感觉暴力比较好打,也可以拿
80
p
t
s
80pts
80pts,同时思考了一下暴力的复杂度是
n
2
n^2
n2,很快写完了,1.5h
第四题感觉很神秘,完全不知道
p
p
p 的意义是什么,思索了一会儿,把前三个打完了,预计
30
p
t
s
30pts
30pts,2h
留了 1.5h 给第一题,思考了 20min 几乎毫无思路,但还是码了一会儿《正解》,发现只剩下 1h 了,感觉不对,赶紧把暴力和部分分拼完,感觉暴力还不好打,拼拼凑凑+卡常,分数
[
30
p
t
s
,
60
p
t
s
]
[30pts,60pts]
[30pts,60pts],只有 20min 了, 感觉很寄
剩下 20min 把所有代码看了一遍
预估分数:
[
30
−
60
]
+
80
+
80
+
30
=
[
220
,
250
]
[30-60]+80+80+30=[220,250]
[30−60]+80+80+30=[220,250]
实际分数:
0
+
80
+
55
+
10
=
145
0+80+55+10=145
0+80+55+10=145
反思
T
1
T1
T1 文件名写错了,不知道自己怎么会犯如此低级的错误,正解没想到不怪我,出题人题意写错了
T
2
T2
T2 老问题,哈希 死活想不到,看到一段区间内数字固定时,需要想到哈希
T
3
T3
T3 输出
u
n
s
i
g
n
e
d
l
o
n
g
l
o
n
g
unsigned\;long\;long
unsignedlonglong 应该是
p
r
i
n
t
f
(
"
%
l
l
u
"
)
printf("\%llu")
printf("%llu"),而不是
p
r
i
n
t
f
(
"
%
l
u
"
)
printf("\%lu")
printf("%lu"),然后有一个重要的转化是
x
⊕
y
=
x
+
y
−
2
∗
(
x
&
y
)
x\oplus y=x+y-2*(x\&y)
x⊕y=x+y−2∗(x&y)
T
4
T4
T4 需要找到一些性质在做题,感觉还是题做的不够
题解
T1
没什么好说的
T2
题目:长度为
n
n
n 的序列,权值是
1
−
n
1-n
1−n 的排列,求有多少个区间
[
l
,
r
]
[l,r]
[l,r] 包含
l
−
r
l-r
l−r 所有权值
n
<
=
1
e
6
n<=1e6
n<=1e6
解法:哈希
T3
题目:给定一颗树,求每个点的子树内距自己距离不超过
k
k
k 的点的点集两两之间点权的异或的平方的和
解法:把
(
x
⊕
y
)
2
(x\oplus y)^2
(x⊕y)2 变成
(
x
⊕
y
)
∗
(
x
⊕
y
)
(x\oplus y)*(x\oplus y)
(x⊕y)∗(x⊕y),考虑对于第
A
A
A 位和第
B
B
B 位的乘积统计贡献,这里用树上差分即可,时间复杂度
O
(
n
l
o
g
2
a
i
)
O(nlog^2a_i)
O(nlog2ai)
核心代码:
for(int A=0;A<=30;A++)//第一个x^y的第A位
for(int B=A;B<=30;B++){//第二个x^y的第B位
for(int i=1;i<=n;i++) s[0][i]=s[1][i]=s[2][i]=s[3][i]=0;
for(int i=1;i<=n;i++){
int t=((a[i]>>A&1)<<1)|(a[i]>>B&1);
s[t][i]++,s[t][kup[i]]--;
}
for(int i=n;i>=1;i--) s[0][up[i][0]]+=s[0][i],s[1][up[i][0]]+=s[1][i],s[2][up[i][0]]+=s[2][i],s[3][up[i][0]]+=s[3][i];
for(int i=1;i<=n;i++)
if(A==B) ans[i]+=(s[0][i]*s[3][i]+s[1][i]*s[2][i])*(1ull<<(A+B));
else ans[i]+=(s[0][i]*s[3][i]+s[1][i]*s[2][i])*(1ull<<(A+B+1));
}
T4
题目:给定
l
,
r
,
p
l,r,p
l,r,p,求有多少整数对
i
,
j
i,j
i,j 满足
l
≤
i
2
+
j
2
≤
r
l\le i^2+j^2\le r
l≤i2+j2≤r 且
p
∣
i
2
+
j
2
p|i^2+j^2
p∣i2+j2
20
p
t
s
:
p
=
4
20pts:p=4
20pts:p=4
30
p
t
s
:
p
=
4
∗
9
∗
(
1
0
7
+
3
)
∗
233
30pts:p=4*9*(10^7+3)*233
30pts:p=4∗9∗(107+3)∗233
50
p
t
s
:
p
=
4
∗
9
∗
(
1
0
7
+
3
)
∗
19260817
50pts:p=4*9*(10^7+3)*19260817
50pts:p=4∗9∗(107+3)∗19260817
l
≤
r
≤
1
0
30
l\le r\le10^{30}
l≤r≤1030
题解:
先考虑
p
=
4
∗
9
∗
(
1
0
7
+
3
)
∗
19260817
p=4*9*(10^7+3)*19260817
p=4∗9∗(107+3)∗19260817,其他情况更简单
考虑证明对于
p
=
4
k
+
3
p=4k+3
p=4k+3,且满足
p
∣
i
2
+
j
2
p|i^2+j^2
p∣i2+j2,
i
,
j
i,j
i,j 一定是
p
p
p 的倍数
证明:反证,若
i
2
≡
−
j
2
(
m
o
d
p
)
i^2\equiv -j^2(mod\;p)
i2≡−j2(modp)
则
(
i
2
)
2
k
+
1
≡
(
−
j
2
)
2
k
+
1
(
m
o
d
p
)
(i^2)^{2k+1}\equiv (-j^2)^{2k+1}(mod\;p)
(i2)2k+1≡(−j2)2k+1(modp)
则
i
p
−
1
≡
(
−
j
)
p
−
1
(
m
o
d
p
)
i^{p-1}\equiv (-j)^{p-1}(mod\;p)
ip−1≡(−j)p−1(modp)
根据费马小定理,
1
≡
−
1
1\equiv-1
1≡−1,矛盾
若
p
=
4
p=4
p=4 可证得
2
∣
i
,
j
2|i,j
2∣i,j
所以
2
∗
9
∗
(
1
0
7
+
3
)
∣
i
,
j
2*9*(10^7+3)|i,j
2∗9∗(107+3)∣i,j,令
q
=
2
∗
9
∗
(
1
0
7
+
3
)
q=2*9*(10^7+3)
q=2∗9∗(107+3)
考虑到
i
,
j
i,j
i,j 的范围已经不大,所以考虑令
i
′
=
i
/
q
,
j
=
j
′
/
q
i'=i/q,\;j=j'/q
i′=i/q,j=j′/q
所以
l
q
2
≤
i
’
2
+
j
′
2
≤
r
q
2
\frac{l}{q^2}\le i’^2+j'^2\le \frac{r}{q^2}
q2l≤i’2+j′2≤q2r
l
q
2
\frac{l}{q^2}
q2l 的范围已经在
1
0
12
10^{12}
1012 以内了
考虑枚举
i
′
(
i
′
≤
1
0
6
)
i'(i'\le 10^6)
i′(i′≤106),可以双指针出
j
′
j'
j′ 的范围,然后记录
m
o
d
m
mod\;m
modm 的余数即可
核心代码:
int m;
if(p==4) l=l/4,r=r/4,m=1;
else if(p==6933896200168236){
int q=2*9*(1e7+3);
l=l/q/q,r=r/q/q;
m=19260817;
}
else{
int q=2*9*(1e7+3);
l=l/q/q,r=r/q/q;
m=233;
}
// l<=i'^2+j'^2<=r
// m|i'^2+j'^2
int L=0,R=0,ans=0;
for(int i=sqrt((long long)r);i>=0;i--){
while(i*i+L*L<l){ sum[L*L%m]--;L++;}
while(i*i+R*R<=r){ sum[R*R%m]++;R++;}
ans+=sum[(m-i*i%m)%m];
}