回家路线(dp)
随便暴力
#include<bits/stdc++.h> using namespace std; int n,m,a,b,c,f[100010][1010]; struct no{ int x,y,p,q; bool operator <(const no &rhs)const{ return q<rhs.q; } }ar[200010]; int gf(int x){return a*x*x+b*x+c;} int main(){ scanf("%d%d%d%d%d",&n,&m,&a,&b,&c); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&ar[i].x,&ar[i].y,&ar[i].p,&ar[i].q); sort(ar+1,ar+m+1); memset(f,63,sizeof(f)); f[1][0]=0; for(int i=1;i<=m;i++) for(int j=0;j<=ar[i].p;j++) f[ar[i].y][ar[i].q]=min(f[ar[i].y][ar[i].q],f[ar[i].x][j]+gf(ar[i].p-j)); int ans=2e9; for(int i=1;i<=1000;i++) ans=min(ans,f[n][i]+i); printf("%d",ans); }
机器人(插值,dp,多项式)
考虑类似分治的思想,考虑当前处理的区间为$[l,r]$
中间最大值点有特殊性:从中间的严格最大值点摆放机器人,能够走遍$[l,r]$,且区间的所有其他点摆放机器人都不能跨过这个点。
(但是下面的方程和这个定义有点不一样)
假设中间最大值点的坐标为$md$,则问题被划分成了$[l,md-1]$,$[md+1,r]$两个子问题。
设$f[l][r][k]$表示区间$[l,r]$,最大值为$k$的答案。则有转移$f[l][r][k]=sum{}{k<=x}f[l][md-1][k]sum{}{k<x}f[md+1][r][k]$
注意到访问的区间数量不多,可以记忆化搜索,拿到50分。
更高的分数需要发掘性质。把值离散化一下。设$f[l][r][p][k]$表示当前区间$[l,r]$,最大值在第$p$段而且为$k$的方案数。
实际上,在同一段($p$相等),答案是一个关于$k$的不超过$r-l+1$次分段多项式。
原因是:当$l==r$时显然是$1$次多项式,发现现在的方程等同于把所有段中的答案做一个$l^k+(l+1)^k+.....+r^k$的累加,这个东西是一个k+1次多项式。
中间的多项式$f[l][r][p]$是两边的多项式乘起来。所以中间多项式的次数是$(md-1-l+1)+(r-md-1+1)+1=r-l+1$
累加计算自然数幂和可以插值预处理系数然后计算。
序列(贪心,堆)
弹跳(最短路,嵌套数据结构)
直接线段树优化连边肯定是不行的。考虑隐式建图。维护一个线段树套set。
每次从堆中取出距离最小的点。接着用这个点更新所有能到的点的距离并且在数据结构中删除。
这样子每个点只会删除/遍历到1次。时间复杂度$O(n log_2^2 n)$空间复杂度$O(n log_2 n)$
斗主地(插值,组合数学,dp)
打表发现答案是二次函数,于是直接插值即可。
证明可看 https://www.luogu.com.cn/blog/ljc1301/solution-p5472
i君的探险(整体二分,随机化)
B类部分分可以使用整体二分。设当前处理的区间是$l,r$,点集为$s$。每次点亮区间$l,md$的所有点,如果当前点的状态改变或者编号$<=md$则放进左边,否则放进右边。
回到原题。这样子可以得到被连奇数次的边。每次随机化即可证明时间复杂度期望$O(n log_2 n)$
证明以后补