20230812 比赛总结

考试经历

先看了一眼第一题,手玩了几个小数据,没发现什么规律,先跳了,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] [3060]+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) xy=x+y2(x&y)
T 4 T4 T4 需要找到一些性质在做题,感觉还是题做的不够

题解

T1

没什么好说的

T2

题目:长度为 n n n 的序列,权值是 1 − n 1-n 1n 的排列,求有多少个区间 [ l , r ] [l,r] [l,r] 包含 l − r l-r lr 所有权值
n < = 1 e 6 n<=1e6 n<=1e6
解法:哈希

T3

题目:给定一颗树,求每个点的子树内距自己距离不超过 k k k 的点的点集两两之间点权的异或的平方的和
解法:把 ( x ⊕ y ) 2 (x\oplus y)^2 (xy)2 变成 ( x ⊕ y ) ∗ ( x ⊕ y ) (x\oplus y)*(x\oplus y) (xy)(xy),考虑对于第 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 li2+j2r p ∣ i 2 + j 2 p|i^2+j^2 pi2+j2
20 p t s : p = 4 20pts:p=4 20ptsp=4
30 p t s : p = 4 ∗ 9 ∗ ( 1 0 7 + 3 ) ∗ 233 30pts:p=4*9*(10^7+3)*233 30ptsp=49(107+3)233
50 p t s : p = 4 ∗ 9 ∗ ( 1 0 7 + 3 ) ∗ 19260817 50pts:p=4*9*(10^7+3)*19260817 50ptsp=49(107+3)19260817
l ≤ r ≤ 1 0 30 l\le r\le10^{30} lr1030
题解:
先考虑 p = 4 ∗ 9 ∗ ( 1 0 7 + 3 ) ∗ 19260817 p=4*9*(10^7+3)*19260817 p=49(107+3)19260817,其他情况更简单
考虑证明对于 p = 4 k + 3 p=4k+3 p=4k+3,且满足 p ∣ i 2 + j 2 p|i^2+j^2 pi2+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) i2j2(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) ip1(j)p1(modp)
根据费马小定理, 1 ≡ − 1 1\equiv-1 11,矛盾

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 29(107+3)i,j,令 q = 2 ∗ 9 ∗ ( 1 0 7 + 3 ) q=2*9*(10^7+3) q=29(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} q2li2+j′2q2r
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(i106),可以双指针出 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];
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值