1.矩阵加速的通法
形式1:dp[i]=a1*dp[i-1]+a2*dp[i-2]+…+a[k]*dp[i-k]
for(int i=0;i<k;i++) A.ma[i][0]=chu[i]
for(int i=0;i<k;i++)
for(int j=0;j<k;j++){
if(i==0) B.ma[i][j]=a[j+1];
else B.ma[i][j]=(j==(i-1))?1:0;
}
形式2:dp[i][j]=a[j][0]*dp[i-1][0]+a[j][1]*dp[i-1][1]+…+a[j][k-1]*dp[i-1][k-1],0<=j< k
求dp[n][0],dp[n][1]…dp[n][k-1],n<=1e9,k<=50
for(int i=0;i<k;i++) A.ma[i][0]=chu[i];
for(int i=0;i<k;i++)
for(int j=0;j<k;j++){
B.ma[i][j]=a[i][j]
}
2.常见dp优化方法
dp[i]=f(dp[j]),1<=j<=i−1
1)尺取法优化
适用于dp的最优解转移沿着特定方向
2)辅助数组法
适用于可以通过适当变换将i和j分离开,数组记录g[j]用于更新dp[i]
3)辅助数据结构优化
dp[i]=min/maxf(dp[j]),h1[i]<h2[j]
解法:将元素按照h1的值从小到大重新排序,由于h1[i]递增,所以不满足
h1[i]<h2[j]
的一定不满足
h1[i+1]<h2[j]
,所以可以使用优先队列维护排好序的前面所有项的最小/最大f(dp)值,并记录相应的h2值,如果队头元素对当前i不满足
h1[i]<h2[queue[top]]
,队头元素出列。进出列各一次,复杂度O(n)
dp[i]=min/maxf(dp[j]),h1[i]>h2[j]
解法:将元素按照h2的值从小到大排序,维护f(dp)值递减/增的序列,对于不满足递减/增性质的f(dp)值舍去即可。原因是h2递增,对于满足
h2[j]<h1[i
]的值一定对于所有的
k<j
都满足
h2[k]<h1[i]
,所以如果当前
f(dp[j])<f(dp[j−1])
,则下标大于j的dp值一定不会通过第j项转移,否则也可以通过第j-1项转移,第j项删除不影响结果,因此最终只要二分查找满足
h2[j]<h1[i]
的最大下标项即可。
dp[i]=f(dp[bisearch(s+1,s+top+1,h1[i])])
,s中存储h2和排好序的数组下标值,对h2进行二分,输出相应下标值。
两者比较可知,如果dp[i]仅与某一项有关,限制条件i和j完全独立,每次都将元素按照限制条件较小的一边重新进行排序即可进行“维护队列”优化
然而上述两中dp形式都可以很容易地通过线段树进行优化,两种方法各有优劣。
如第二种形式,先将所有f(dp)值按h2的值为下标插入线段树中,然后每次询问小于h1[i]的f(dp)最小值,从复杂度O(n*logn)
从而我们联想到此种dp的通法:
**形如
dp[i]=min/max/sumf(dp[j]),h2[i]<=h1[j]<=h3[i]
,我们可以通过线段树/树状数组进行优化求解。
min/max:线段树求解。在h1值上建立以f(dp)为值的线段树,将所有值插入后,每次更新dp值时询问h2[i]-h3[i]区间内的min/max值即可
sum:同理建立树状数组,每次询问区间和即可
栈或队列优化题目汇总
1)求l[i]:第i个数左侧个小于i位置元素的最大位置
维护单调栈即可
3.实际简化模型
1)三角简化
元素中两两之间只有两种互斥关系A和!A,求三个数之间两两为A或两两!A的三元组数目
C(n,3)-
∑ni=1a[i]∗(n−1−a[i])
,a[i]是与第i个元素关系为A的数目
常见问题求解方法
1)连续区间的求和统计问题:以区间和为主元,统计以“某点开始”、“相等区间和”对应的权值和。因为连续区间满足连续变化的性质,所以可以采取尺取法统计。
2)字符串问题
预处理Hash(i):前i个字符的哈希值,可以在O(1)得到字串hash值
3)二分答案
1.求
min(max(f(xi),1<=i<=n)),g(x1,x2...xn)=0
二分答案。令min值为L,判断是否存在
max(f(xi),1<=i<=n)<L
。判断方法如下:将n个不等式处理后相加凑成
g(x1,x2...xn)
,将g函数放宽为
>=0
,可以得到L和参数之间的关系,二分答案L即可得到恰好满足不等关系的最小L,如果不一定恰好取等,先令每个f(x_i)=L,然后再对每个
xi
进行缩小使得满足g函数等式关系。
2.求
max(f(xi1,xi2...xik)/g(xi1,xi2...xik)),1<=i1<i2<...<ik<=n
令max值为L,判断是否存在序列满足
max(f(xi1,xi2...xik)/g(xi1,xi2...xik)
大于等于L.可以通过建图,网络流求解方法
4)计数问题
概率法解决计数问题:设总的方案数为sum,满足条件的概率为p,那么满足条件的计数为ans=p*sum。如此一来就把计数问题转化为概率问题!
3.dfs的应用
1)动态记录访问到当前节点时的所需信息(仅在进入该节点时定义为访问),然后在入戳和出戳时分别记录当前节点的信息,比较差距即可得到以该点为根的子树的所需信息总和
4.生成树问题
1)无向图多组询问,从u出发仅经过长度不大于x的边可到达的点的个数
解法:利用kruskal算法建立最小生成树,在合并两点x和y所在子树时,着大x和y所在子树的跟fx和fy,然后让它们同时指向新节点f,f赋值为该边权值,最终得到2*n-1个节点。这个生成树的性质为:从深到浅,权值不断增大。可以查找从u到根节点权值小于x的最大节点f,f子树节点即为u所能到达的节点集合。求节点数量的话,先预处理子树大小或者记录dfs序都可以