前缀和杂题思路
前缀和杂题思路:
P3397:二维前缀和板子,直接暴力枚举
P3131:预处理前缀和,将7的余数用桶存进来,然后扫一遍取maxx(当两个位置的前缀和%7同余时,这一段整除7)
P1387::这是前缀和?建议使用DP
P3406:手搓画图,使用差分将每一段走的次数预处理出来,然后使用贪心,判断哪个更为划算
P1934:前缀和优化DP,将前缀和预处理出来,dp[i]初始化为 a[i]* n*n,然后当a[i]+a[j]<=t时更新dp,注意每一次更新完后还可以使用攻击一层的方式。
dp[i]=n*n*a[i],dp[i]+=dp[i-1]
dp[i]=min(dp[i],dp[j-1]+(sum[i]-sum[j-1])*(a[i]+a[j]))(a[i]+a[j]<=t)
dp[i]=min(dp[i],dp[i-1]+n*n*a[i])
P3662:处理前缀和,然后用一段长度为k的区间截。
P1182 :二分答案板子题
P4825:递推,模拟要求,然后用dp数组转移,初始化\(dp[1][1]=1\)(四维递推)
P5542:一开始没有看清范围,暴力前缀和处理就是了,x,y不会超过1000
P4086:要找的是最大值,暴力模拟,前缀和预处理即可
P2697,P1114:好像还有一道Codeforces来着,两种颜色一种设为1,另外一种为-1,前缀和处理,然后将不同前缀和放在一个桶中记录,思路同P3131,但是由于可能会出现负数,桶数组开两倍记录,ans扫一遍,没有就记录当前位置,有的话判断是否可以更新ans,由于桶内装的是这个前缀和最早出现的位置,所以利用贪心的思想,是最优的。
P3353:暴力前缀和,题面好评。
P6191:感觉有些DP简单题和前缀和混一起了,由于在前k个,可以随便放都不会出现冲突,而k个之后\(dp[i]+=dp[i-1]+dp[i-k-1]\)
DP递推式:
\(dp[i]=i+1 (0-k)\)
\(dp[i]+=dp[i-1]+dp[i-k-1](k+1-n)\)
P1865:要会素数筛,筛一遍然后前缀和统计输出
P3909:祖宗题,完全不会推式子,需要自己手推式子,利用前缀和更新。(不会的看题解)
P1083:二分答案板子题,每次查询利用差分和前缀和,判断是否有小于0的情况
P9587:祖宗题+1, 将数组从大到小排序,预处理出前缀和,如果当前的正好是第k个,答案为0,如果小于第k个,那就加到第k个,答案\(p[k].x-p[i].x\),如果大于了第k个,那么要将上面的全部减去,答案为\((k-i)*p[i].x-sum[k]+sum[i]\)
P2213:旋转四十五度进行计算,这个时候距离为原来的两倍,所以\(k*=2\),注意判断k比地图大的特殊情况(旋转45度 \(mapp[i+j-1][n-i+j]=a[i][j]\))
P3948:暴力计算q(q<=1e3)次询问,然后处理操作完后的前缀和,延后的操作\(O(1)\)完成
P9460:二分答案练习题,先将输入的数放入桶中,以一开始需要多少个这样的数为二分答案的目标,然后是check函数,每一次check x首先加k(因为无论选择哪个,最终mid都会加k),然后遍历计数数组(计算每个数出现的次数),如果发现大于x,就把多出来的部分记下,最后把记下的数与 k 比较就行了。注意一下,若最后二分出的数为零,输出正无穷(也就是 pigstd)
P2280:二维前缀和板子题
P9681:祖宗题+2,题面可以写的再高级一点,首先前面不能超过0,但区间可以大于0,那么符合条件的就是前面全是非正数,最后一个是正数。预处理所有的正数判断它可以一直加到哪一个负数才小于0,这时候要用前缀和,二分出最远的下标(但是如果一直到前一个正数,相加起来还是大于0的话,那么最远下标就是前一个正数+1),然后询问的时候同样二分出区间,统计答案。
P3173:什么前缀和,使用贪心,将横竖放在一个结构体中,从大到小排序,依次切割,相加就是答案。
P3138:会用到离散化(因为我们只用看相对大小),然后前缀和预处理,再暴力枚举每一个点,进行答案的统计与更新。
P3068:模拟,多跑几遍。
P2671:由于数据较大,所以使用vector当桶,注意到其说\(y-x=z-y\),即\(2y=x+z\),所以x与y必须是同奇偶的,开m种颜色的桶,每个颜色又分为偶数与奇数两个桶,将每个下标放在满足要求的桶内,然后开始推式子,显然可以发现,每个桶只有size>1的时候才可以做出贡献,对于每一个桶,算出它存的下标的总和\(res\),那么每一个桶里的下标做出的贡献就是\((res+(len-2)*t[i][j])*num[t[i][j]]\),其中\(len\)是桶的大小,具体细节见代码。
P9588:我谔谔,STL大法,使用多重集multiset,对于每一次操作一,就相当于是a数组在当前下标+1处赋上x,即\(a[++cnt]=x\),每一个\(a[i]\)代表了这里有多少个数,同时\(sum=sum[i-1]+a[i]\)记录前缀和,每一次操作一里面加入的最大的数就是x,把它放入多重集multiset里。操作二用一个全局变量res记录总共删了多少就好,利用前缀和数组删去应该删去的操作一中最大的数x。操作三,首先加上已经删去的下标res,然后二分查找。操作四就在多重集里找最大值 \(mapp.rbegin()\)
P2629:首先破环为链,开两倍数组,然后记录前缀和,使用单调队列维护。
P3819:小学奥数题,结论显然。
P4712:贪心,由于每一次的传递伴随着大量的能量损耗,所以可以吃生产者时就吃生产者,我们的目标是让自己获得的能量最多,所以下面的捕食者获取到可以生存的能量就可以了,每一次输入,生产者减去捕食者所需的能量,同时建立一个捕食者被捕食时的数组f,\(f[i]+=p[i].a/5+f[i-1]\),捕食者可以捕食的生物单调不减,所以可以使用前缀和维护,当生产者被吃完的时候就利用数组f的能量,计算最后的答案,在此过程中,如果有哪一个捕食者摄入不到生存的能量就直接输出-1,跳出程序。
P1314:推了很久,自己真的是不会做绿题了,二分答案,找出离s最近的值,在每一次二分的时候做前缀和,扫一遍满足条件的w[i]。然后将每个区间加上就可以了。
P4623:差分的板子题,将每个三角形的三个点输入时预处理出最大与最小的x,y坐标,然后用不用离散化都行,值域并不是很大,注意x,y分别用两个差分数组。
P1428:差分的差分板子题,由于等差序列等差,所以\([l,r]\)间加上一个等差数组,就相当于在\([l,r]\)对应的差分数组加上公差,但是第一个与最后一个要特殊计算,第一个要加上首项,最后一个的后面一位数组要减相应的值,把前面加了的减回来。去维护差分数组,保留原数组,这样我们就把修改操作转化为区间修改,询问每个点相当于是查询区间\([1,x]\)再加上这个坐标本来的值。可以使用线段树去维护。
P4085:还是一道转换为数据结构维护的题,预处理出f的前缀和,所有的\(f[i]>0\),所以前缀和单调上升,我们可以通过二分查找找到当前下标i最近的满足条件的点,用lower_bound就可以了,然后由于是查询一个区间内\(s[i]\)的最大值,那我们就使用线段树维护,查询。最后ans取所有区间最大中最小的那个。
P8666:多维上差分的板子,这个三维可以画画图,多维就记一下公式。
P4231:一道祖宗题,和P1428非常类似,但是P1428只是查询其中一个点的值,这道题是要我们知道每一个点的值,所以只能通过差分上的差分数组,设g为公差,s为首项,修改区间\([l,r]\),对应到差分的差分数组c就是
c[l]+=s,c[l+1]+=g-s;
c[r+1]-=g+e,c[r+2]+=e;
想要得到原本这个下标上表示的值,就需要做两次前缀和,然后ans扫一遍统计答案。
P6537&P2363:wtcl,是一类思想,建议看题解。
P9744:一道非常巧妙的贪心与前缀和结合的题,留给读者思考。
P4868:之前是差分的差分,现在是前缀和的前缀和,将式子转化一下,那么在i处加上一个数就是在前缀和数组上加上x,在前缀和的前缀和数组上加上\(x*i\),那么这个可以用树状数组来维护,用两棵树,一个是前缀和,另一个就是前缀和的前缀和,查询同理。
P3258:可以用树上差分,其实这就是一道树链剖分板子题。
P8572:祖宗题,由于n与k都只说\(<=5e5+5\),空间明显爆炸,但是有\(n*k<=5e5+5\)的限制,可以考虑使用根号分治。
题面:
给你 \(k\) 个长为 \(n\) 的序列 \(a_{1\dots k,1\dots n}\),有 \(q\) 次询问,每次询问给出一个区间 \([l,r]\),要求出 \(\displaystyle\max_{i=1}^k\sum_{j=l}^ra_{i,j}\),即求出所有序列中区间 \([l,r]\) 的和的最大值。
由于根号分治,分两种情况:k<=750与k>=750
先预处理出每一行的前缀和。
对于第一种情况,此时\(k<=750\),说明最多有750行,询问次数是5e5级别的,那么对于每一次的询问,然后暴力扫\(sum[i][r]-sum[i][l-1]\),得到最大值,时间复杂度是\(O(qk)\) 但由于\(k<=750\),最坏计算次数在5e8左右,可以过掉。
对于第二种情况,很显然,如果还是用第一种方法的话时间会爆炸,那么我们直接预处理出来当询问区间为\([l,r]\)时,答案为多少,这样在回答每一个询问的时候时间复杂度为\(O(1)\),总共为\(O(q)\),那么应该怎么预处理?枚举左右端点,然后像第一种操作那样暴力从1扫到k,取\(sum[i][r]-sum[i][l-1]\)的最大值,赋给\(ans[l][r]\)。为什么不会超时,由于左右端点都是小于n的,每一次取好左右端点后暴力找最大值运行k次,所以总的时间复杂度是\(O(n^2k)\)的,n此时\(<=750\),最坏的时间复杂度大概也在5e8左右,可以过掉此题。
P4734:没翻译,留作思考题。
P4552:蓝书上的例题,严谨的证明在下还不会,那就只能找规律记结论了。
P4998:有点坑,我是利用类似于树形DP的思想,由于信号站可以建在负坐标上,暴力算出在-1e6时的答案,然后一个一个坐标往左移,预处理出当前坐标左边有多少户人家,右边也就同时得到了,设左边有l个,右边有r个,那么\(ans[i]=ans[i-1]+l-r\),最后将这些坐标排个序,然后将最小的m个加起来就是答案。
P6627:一看数据范围,肯定需要离散化,同时,一开始这道题我想错了,下面给出我错误的思路,离散化之后按照每一种操作的要求,模拟着做差分,由于一个数异或两次同一个数,值不变(即\(a^a^b=b\)),直接利用其做差分,然后最后做前缀和,一个个异或过去,找到最大值。取得了
65分的好成绩。那为什么这种思路是错的,因为煞笔出题人在然我们输出对应最大值的幸运数字时搞了一堆奇奇怪怪的东西。所以正解需要使用数据结构维护。
P3608:树状数组维护大小的板子题,有一些细节。