[离线处理][scheduling][数论结论][x] HDU5869 Different GCD Subarray Query

题目链接

题意:

给定 $N$ 个数字, $Q$ 次询问,每次询问为查询下标在 $[l,r]$ 之间的所有数字中所有可能的子段的 $gcd$ 有多少种。$N,Q < 10^5 , a_i < 10^6$

题解:

首先一个重要的结论:以固定点为结尾的子段的 $gcd$ 种数不超过 $max(n,log(max(a_i)))$ 证明:每次往原有的序列里加入一个数字的话, $gcd$ 要么不变,要么至少变为原来的1/2,因此为指数级减小。

有了这个结论,我们可以试着来枚举一个端点考虑本题,不妨枚举每个段的右端点$r_j$ , 假设集合$S$表示以$r_{j-1}$ 为结尾的所有 $gcd$ ,那么要求出以$r_j$为结尾的所有 $gcd$ ,只需遍历S中的每个数字$d_k$,计算其与$a_j$ 的 $gcd$ ,放入新集合$S^{‘}$即可。这样的话我们可以得到一个空间为$O(nlogn)$的结果,表示以每个点为结尾的所有段的 $gcd$ 都是哪些数字。

现在来考虑查询。每次查询的话是要求出来$[l,r]$之间所有可能的 $gcd$ 。直接暴力不可取,由上面的结果可以试着考虑能否转化为前缀问题。可以发现,如果我们对所有的$[l,r]$离线处理,按$r$从小到大排序,并且按照这个顺序来调整已经遇到过的 $gcd$ 的信息的话,每次的查询只需要考虑有多少个 $gcd$ 出现的最右左端点大于等于l,这句话具体的意思是,一个 $gcd$ 可能出现过了很多次,不同的段都可以得到这个 $gcd$ ,但是我们只考虑这些段中左端点l_j最大的那个点$p_j$,这样的话如果$l<=p_j$那么可以确定$[l,r]$中一定有这个 $gcd$ (种类+1),这就就转化成了一个计数问题。 继续阅读“[离线处理][scheduling][数论结论][x] HDU5869 Different GCD Subarray Query”

[补题][数位dp][位运算] 2019牛客第七场 H Pair

题目链接

题意:给定ABC三个数,大小1e9,要求求出来1<=x<=A,1<=y<=B范围内满足(x&y)>C或(x^y)<C的(x,y)对数。

由于题目给的是或条件,所以还要考虑一个容斥的问题,先算出来单独满足两个条件的数目,再减去同时满足两个条件的数目,即可得到答案。先考虑单独计算两个条件的情况:

一般来说这种数位dp的框架都是类似的,在第i位时考虑前面的约束有没有“顶满”,如果顶满的话考虑当前这一位的限制,否则继续递归下去。这样的框架使得最后的递归边界处理变成了最有思维含量的一部分。这个题不同寻常的地方在于它是强制要求你同时考虑多个边界的,这是值得注意的一点。在这个题目里比较友好的一点是他对于与C的关系比对的时候是不等号,没有等号,这样的话,我们只要在dp计数的过程中一直保持可行性就可以了,到最后一步(pos=-1)只需要判断

1)前面是不是顶到C的头了,如果是的话就不行
2)前面是不是顶到了全0,因为题目要求x,y至少为1
继续阅读“[补题][数位dp][位运算] 2019牛客第七场 H Pair”

[DP][字符串匹配][子序列] codeforces 1150 D Three Religions

vp了这一场,这个D题难到出现断层。。。C过了1k人的时候D没人过,太狠了

主要是能想到用dp搞字符串匹配的。。。div2里这样的人应该不多吧

但是这个题其实内涵里有诱导dp的思想:刚开始没有搞懂他这里的append是什么意思,后来才懂得他每次的+-操作都是在修改对应的religion的描述,这个描述是一个只有小写字母的先后顺序固定的字符串。。然后题目问的就是给定你一个字符串叫做word of universe,问3个religion能不能共存,其实意思就是能不能从这个word of universe分离出来三个subsequence,他们互不相交,又正好是3个religion的描述。

vp的时候毫无头绪,正解里的预处理表倒是想到了也写了但是没用上。确实没想到会是dp emmmm 。既然dp那一定有个数值型的对象吧,他这里就很妙的把问题转化为满足这三个subsequence共存的序列至少要多长了。。。当然给定的word of universe是确定的,这里其实可以认为后面还有无限长的字符串。。。但是长度大于n的时候我们认为没用了。。就输出NO就可以。不得不说确实是很精妙,legendary出的题确实厉害👍

具体地,设dp(n1,n2,n3)为region1满足前n1个字符,region2满足前n2个,region3满足前n3个这样的情况下所需要的在word of universe里的前缀至少有多长。有一个暴力的计算O(250^3)复杂度的,就是

\[
dp\left(n_{1}, n_{2}, n_{3}\right)=\min \left\{\begin{array}{ll}{Nst\left(dp\left(n_{1}-1, n_{2}, n_{3}\right)+1, \text{description}_{1}\left[n_{1}\right]\right)} & {\text { if } n_{1} \geq 1} \\ {Nst\left(dp\left(n_{1}, n_{2}-1, n_{3}\right)+1, \text{description}_{2}\left[n_{2}\right]\right)} & {\text { if } n_{2} \geq 1} \\ {Nst\left(dp\left(n_{1}, n_{2}, n_{3}-1\right)+1, \text { description }_{3}\left[n_{3}\right]\right)} & {\text { if } n_{3} \geq 1}\end{array}\right.
\]

继续阅读“[DP][字符串匹配][子序列] codeforces 1150 D Three Religions”

[DP][思维][×] codeforces 1183H Subsequences (hard version)

题目链接

题意:给定一个字符串S,长度为n≤100,然后定义一个操作是将S的一个含有L个字符的子序列看作一个字符串插入到一个无重复元素的set里,每次操作的cost是(n-L),然后问对于给定的k(k最大可取1e12),最少需要多少总cost才能使得set的元素个数达到k。难度2200分,有点虚高其实,不过还是不那么好想的。用先后顺序去重是关键idea。

做这种代码段但是考思维的小题还是挺有意思的。。。。

这题是mike出的,感觉挺经典那种。他有一个easy version是k≤100,这个要求的话就很松了,mike的题解直接用了一种及其暴力的方法:把每个subsequence当作一个点,相差一个字符的点之间连边建图,直接暴力跑bfs。。。这个肯定是个时间和空间复杂度都爆炸的算法,但是k≤100的时候很快就能搜到,只要及时跳出bfs就可以了。

这个H版本要求k最大可能是1e12,这就不能再那么操作了。首先写几个简单的样例就可以发现这个主要跟unique的子序列的长度和数量有关系,如果我们能求出来对应于某一长度j的unique子序列有多少个,那就可以解决这个问题了。这个就是一个引导方向,可以先试着设dp[i][j]表示以i为结尾的长度为j的子序列个数。状态定义好了之后考虑转移,按照大问题转化为小问题的思想,dp[i][j]表示的以i结尾的unique子序列,那么如果去掉s[i]之后这些子序列一定是互不相同的长度为j-1的子序列,数量没有多也没有少。所以现在就是要考虑怎么算出来前i-1个字符构成的子序列里面有多少个了。利用已经计算得得信息,这个一定是某些dp[pos][j-1]之和,但是有一种情况的是不同的pos对应的子串可能一样,所以这个题目最精彩的部分就来了,每次在相同的字符中选取最靠后的作为计算点。第一这样起码不会比选择前面的点坏,如果前面的点能凑成q个子序列那么后面的点凑成的相同长度的子序列只会多不会少,即不漏;第二这个就避免了重复计算的现象,不重不漏即为正确的dp转移。所以如果用\[lst[i][w]\]表示前i个字符里面字符为\[‘a’+w (w \in [0,25])\],可以写出来状态转移方程为

\[dp[i][j]=\sum_{w=0}^{25} dp[lst[i-1][w]][j-1]\]

至于lst显然很简单的一个dp就推出来了lst[i][j]=((int)(s[i]-‘a’)==j)?i:lst[i-1][j];
继续阅读“[DP][思维][×] codeforces 1183H Subsequences (hard version)”

[比赛补题][FFT][组合数学][母函数][×]2019 xdu网络赛F XDOJ 1409: 背包弹夹平底锅

2019 xdu网络赛F XDOJ 1409: 背包弹夹平底锅

题目链接

网络赛最难的一个题,也是我唯一一个不会做的。

看了大大的题解发现我其实已经推到了倒数第二步T_T

但是眼拙没看出来可以写成卷积形式。。。所以按照那个推法无论如何都是O(n^2)的复杂度,变成卷积形式就可以用fft加速直接O(nlogn)一次性求出所有点的值了。。。
继续阅读“[比赛补题][FFT][组合数学][母函数][×]2019 xdu网络赛F XDOJ 1409: 背包弹夹平底锅”

[比赛补题][×] 2019 ICPC南昌邀请赛网络赛 K MORE XOR

2019 ICPC南昌邀请赛网络赛 K MORE XOR

题目链接

(⊙﹏⊙)不知道为什么比赛时候这个题和D题死推不出来,比赛完了5分钟ac,我大概脑子坏掉了。真的是超超超超级简单的一个题,但是我光顾着用数学公式推了所以推出来结果巨复杂(⊙﹏⊙)服了自己了。

题解:先说怎么求g(l,r): 首先f(l,r)很好求,利用异或的性质,预处理出来前缀异或和就可以了。设预处理出来p1[x]表示从a[1]到a[x]的异或和,那么很容易得到\[f(l,r)=p1[l-1]\oplus p2[r] \], 那么可以由g的定义就可以知道 \[ g(l,r)=\sum_{i=l}^{i=r} \sum_{j=i}^{j=r} f(i,j) =\sum_{i=l}^{i=r} \sum_{j=i}^{j=r} p1[i-1]\oplus p1[j] \];当然这个东西还是很复杂的,我们想办法把他复杂度搞到O(1):考虑每个p1[x]出现的次数,列个表可以发现,在这个求和式中出现的所有下标,从l-1变化到r, 而每个下标出现的次数都是一样的,这个次数等于 r-l+1 ,那么就可以得出结论,如果r-l+1为偶数,则g(l,r)应为0,否则应为\[ \sum_{i=l-1}^{r} p1[i] \],注意到这个式子又可以用p1的前缀和来O(1)计算,所以又可以提前求出来p1的前缀和p2,这样的话g(l,r)就可以表示为

\[g(l,r)=
\begin{cases}
0& \text{(r-l+1) is odd}\\
p2[l-2]\oplus p2[r]& \text{else }
\end{cases}\]

有了g(l,r)再来考虑w(l,r),\[w(l,r)=\sum_{i=l}^{i=r} \sum_{j=i}^{j=r} g(i,j) \],就跟g的表达式很像,但是这里不能直接再套用g关于p1的公式,因为g里面有很多的0是跟p2无关的,换句话说这些0并不是由p2[l-2]^p2[r]求出来的,所以要分类讨论。分析方法跟g是类似的,列一个表观察每个p2出现的规律,可以发现,这个规律是4个一循环的结构,设\[t=(r-l+1)\mod 4\]; 则当t==0时,所有的p2下标出现次数均为偶数次,也就是结果一定为0,t==2时,所有的p2下标出现次数均为奇数,这样的话即等于\[\sum_{i=l-1}^{r} p2[i] \],这个式子说明我们可以再用一个p2的前缀和p3来O(1)计算这个结果。这是比较简单的两种情况,另外两种是t==1和t==3,这两种一种是奇数项的出现次数为奇数偶数项为偶数,另一种是奇数项出现次数为偶数而偶数项出现次数为奇数,这意味着可以用一个分奇偶的前缀和来O(1)求得这个式子只不过仍需要分类讨论一次。。若令p31[i]和p32[i]分别表示p2的奇偶前缀和,t=(r-l+1)%4, 则w(l,r)的表达式为

\[
w(l,r)=
\begin{cases}
0& \text{t=0}\\
p31[r]\oplus p31[l-3]& \text{t=1 and r is odd}\\
p32[r]\oplus p32[l-3]& \text{t=1 and r is even}\\
p3[l-3]\oplus p3[r]& \text{t=2}\\
p32[r-1]\oplus p32[l-2]& \text{t=3 and r is odd}\\
p31[r]\oplus p31[l-3]& \text{t=3 and r is even}
\end{cases}
\]

这样的话整个问题就可以O(1)解决了。。不知道我当时脑子怎么回事就没推出来
继续阅读“[比赛补题][×] 2019 ICPC南昌邀请赛网络赛 K MORE XOR”

[数学][组合数学][母函数][比赛补题][×] ZOJ 4069(2018 青岛现场赛 L) Sub-cycle Graph

题目链接

这个题一开始想歪了一直在想polya。。。带了半天队友节奏最后俩人都没整出来。

其实一开始就不该被给出的示意图带着走的,当时已经想到了剩下的是n-m段,但是关键在于没有想到怎么处理排列的去重。。。试了下用母函数分配出入度后来发现无法去除已经有圈的情况于是放弃。。其实这时候该想想能不能换个方向用母函数,哎,总的来说还是太菜,做组合数学还是不行。

后来想了下,可以先完全去掉所有的标号,也就是说把所有的点当成同一种点,然后去解决把这n个点分为n-m条链的分法,最后把标号还原回去只需要乘以一个n!的全排列系数就好了。

这时候问题转化为n个相同的点,分为n-m个链条(单个节点自身也是一个链条)的分法,而且这种分法要考虑到空间对称(参考样例)。我们可以设普通型母函数\[F(x)=a_0+a_1x+a_2x^2+…+a_nx^n\]来表示一条链的情况,幂次等于这条链条有多少个节点。由于不认为0个节点是一个链,所以\[a_0=0\], 然后当节点数多于1的时候由于空间对称要除以2,所以除了\[a_1\]之外所有的a都是1/2,也就是说对于一条链其母函数就是\[F(x)=x+1/2 x^2+1/2 x^3+1/2 x^4+….+1/2 x^n\]

得到了一条链的F(x),由母函数的性质可以得到k条链\[(k=m-n)\]的情况就是\[F(x)^k\]的结果中\[x^n\]的系数,只不过还要乘以一个\[n!\]的系数(因为我们之前把所有球都当作一样了所以要乘以一个全排列)再除以一个\[(n-m)!\](因为每次算出来的是所有可能的组合情况,但是这k条链条是不用排序的)

现在的话就是如何计算\[F(x)^k\]的结果中\[x^n\]的系数了,直接暴力肯定超时,考虑把\[F(x)\]的函数变换成更简单的形式。由级数的知识可以知道|x|<1时,\[ F(x)=(x-1/2 x^2)/1-x\] , 那么\[F(x)^k=x^k(1-1/2 x)^k/(1-x)^k \],\[x^k\]好处理,这说明只需要求剩下的部分的\[x^(n-k)\]的系数就行了。看剩下的部分,这里的分母看上去很难操作,但是可以再用级数的方式变换一下 \[1/(1-x)=(1+x+x^2+x^3+x^4+…+x^n)\], 也就是说要求的部分变成了 \[(1-1/2 k)^k (1+x+x^2+x^3+x^4+…+x^n)^k\], 后面的这一坨\[1+x+x^2+x^3+x^4+…+x^n\]可以认为是一次一次乘到前面的。前面的\[(1-1/2 x)^k\]可以用二项式展开,每一项为\[C_k^{i} (-1/2 )^ix^i\] 。这时候考虑计算“二项式展开中第i项对于最终结果的第j项的贡献度(i<=j)”,可以想象一下i变成j是因为加了j-i个1次幂,而总共后面乘的是k个多项式,那么所有的情况也就是中学常学的“把j-i个物品分成k份允许有空集的分法”组合问题了,答案是\[C(j-i+k-1,k-1)\],当时高中数学老师管这叫插隔板法还是什么来着emmmmm。这时候就容易计算了,在算贡献的时候再带上(-1/2)的i次幂就行了。。。

确实是不好想,尤其是在现场赛的环境下,感觉自己还是得更多的做难一点的题目。

继续阅读“[数学][组合数学][母函数][比赛补题][×] ZOJ 4069(2018 青岛现场赛 L) Sub-cycle Graph”

[字符串][Trie][x] UVALive 5913 Dictionary Size

前后缀处理与去重

题目链接

题意:给出n个字符串,要求求出所有的前后缀组成的字符串种类数。

思路:比较简单的一题。 用Trie存储所有的字符串,可以算出所有不同的前缀数,然后把字符串全部反向再插入到另一个Trie,得出所有的后缀数量。二者相乘可以得到所有的可能结果,但是会有重复,所以要去重。去重也很简单,画一画样例可以看出来一定是算出来两个Trie里面的相同的字符出现的次数,每一个字符结点出现一次就会有一个重复,这样减去所有的重复即可。但是直接这样算会有错误,因为可能会产生有的前缀为空后缀为一个不完整字符串,这样是不满足题目要求的,所以在统计结点数量的时候只统计长度大于1的结点(在Trie里深度大于1),然后这样构造出来的全部是满足要求的字符串而且没有重复,但是仍然有一个bug是有的字符串只有一个字符,而上述方法是只能构造出来最小长度为2的字符串的,因此要另外处理这些长度为1的字符最后加到答案里。

继续阅读“[字符串][Trie][x] UVALive 5913 Dictionary Size”

[CF][二分查找][×] codeforces 448D Multiplication Table

写这个题为了提醒自己先想简单的做法再想复杂的,不要一上来就跑偏到复杂操作上去。。。

题目要求给出n*m的乘法表中第K大的元素,n和m都是5e5数量级. 暴力显然不行,所以得找个快速的方法分辨出第k大,然后我由于这几天一直在搞数论,脑子抽了从质因数分解的角度考虑结果弄得巨复杂。。。最后看官方题解就一句话二分查找,醍醐灌顶。。。

由于生成表格的方法是i*j所以check只要把所有的x/i加和与k比较大小就是了。
继续阅读“[CF][二分查找][×] codeforces 448D Multiplication Table”

[组合数学][数论][矩阵][优化][Polya][状压DP][x] XDOJ 1296 敬老师的手环II

去年校赛的时候感觉此题难的一批,,,昨天做polya练习题的时候做到了poj 2888去翻了下matrix67大神的十个利用矩阵乘法解决的经典题目中的第9题才恍然大悟。。。Oooooor2 做完这俩题再来看XDOJ的这个题已经是自然而然就可以搞出结果的了。

这个题的思想就是:把每一列3*1的小方格当成一个“珠子”,把他可能的8种情况当成“颜色”,然后这些颜色同时也代表状态,类似于poj2888的颜色相邻限制,这里的状态之间“能不能相邻”其实就是在状压dp里“能不能转移”的限制,不同状态之间的转移图如下(来自matrix67的那篇文章

继续阅读“[组合数学][数论][矩阵][优化][Polya][状压DP][x] XDOJ 1296 敬老师的手环II”