100里程碑!!!
2.4 acwing.1230. K倍区间(蓝桥杯第八届B组)
1 | 给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。 |
思路:
在比赛时,未必能一下就想到最优的解法,可以先从简单的暴力做法写起,拿到一部分分数,不要放弃。
对于第三重循环计算一段区间的总和,可以用前缀和简化。
有了如下想法:
1 | for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + a[i]; // 求前缀和 |
但这样时间复杂度是:O(n^2),还不够优秀。
我们枚举了左端点和右端点,可以进一步优化:只枚举右端点。
上面的循环写法等价于:求s[r]%k == s[0~r-1]%k
。
这个式子的意思就是:在模k的意义下,求之前所有点和当前点有多少个相等。(有点DP的味道!)
我们发现可以存余数来判断是否满足要求,则可以优化成O(n)。
先开一个数组cnt[i]来存余数是i的数有多少个,用空间换时间。
附上一份高赞题解:https://www.acwing.com/solution/content/6909/
我们可以用一个数组cnt,规定cnt[i]
表示当前位置之前,前缀和取模后等于i的个数,以后每出现一次前缀和(取模后)和它相等,那么k倍区间就加上cnt[s[i] % k]
,然后cnt[s[i] % k]++
。
res += cnt[s[i] % k];
先执行,因为要判断当前区间右端点的左边的同余元素,再更新当前位置。
cnt=0
必须加上,当右端点为1时,若刚好是k的倍数,此时答案应该+1,若没有这句不会+1。
代码:
1 | // y总题解 |
补充:有关段错误的调试方法,使用exit(0)
进行二分判断出错位置。
对于类似的没有输出信息的错误都可以采用这种二分找错的方法。
三 数学与简单DP
1.数学问题
关于数学问题,OIwiki是个好东西!
1.1 acwing.1205. 买不到的数目(第四届A组)
1 | 小明开了一家糖果店。 |
思路:
这是一个非常经典的问题,可以当作一个定理来用。(靠数学积累了)
先分析一下:
根据学过的代数知识,对于给定的数n,m,显然有:$(n,m)|n,(n,m)|m$,推出:$(n,m)|xn+ym$
也就是说,n和m的线性组合一定是(n,m)的倍数,只有这种情况才有解。
给定a,b,若d=gcd(a,b)>1,则一定不能凑出最大数。答案要求a,b互质!
为什么呢?
如果d=gcd(a,b)>1,那么一定可以找到一个极大的数t,满足$(a,b)\nmid t$,这个数可以无限大,所以无解;
而如果d=gcd(a,b)=1,那么所有极大的数t一定满足$1\mid t$,这是显然的,所以有解。
没思路?试试打表找规律!(对于数学问题,没思路不妨试试打表)
补充知识:裴蜀定理,https://oi-wiki.org/math/bezouts/
是一个关于最大公约数的定理。
其内容是:
设a, b是不全为零的整数, 则存在整数x, y,使 $a x+b y=\operatorname{gcd}(a, b).$
证明过程看上面链接。它的一个重要推论是:a,b互质的充分必要条件是存在整数x,y使ax+by=1.
其实在高等代数的多项式部分有相关的定理、结论。
尝试dfs打表:
1 |
|
m表示当前要凑的总数量,如果m == 0,就表示m已经被凑出来了,否则枚举当前选哪种糖,如果选p并且m - p可以被凑出来,那就是说明m可以被凑出;同理如果选q并且m - q可以被凑出来,那就说明m可以被凑出。
找规律:固定p不变,观察q变化时,答案怎么变化,再固定q不变,观察p变化时,答案怎么变化
1 | 2:n+2 m+2 |
找到规律直接给出代码:
1 | // 证明比较复杂,以后可以当作结论直接记住 |
总结:
引理:给定a,b,若d=gcd(a,b)>1,则一定不能凑出最大数。
结论:如果 a,b 均是正整数且互质,那么由 ax+by,x≥0,y≥0 不能凑出的最大数是 (a−1)(b−1)−1。