停课日志 part1 2024.10.21-10.25
10.21
次短路
- 1.dijkstra用两个dist数组记录最短路和次短路 适用条件:严格/非严格 非简单
- 2.dijkstra跑出最短路,保存路径,枚举删除路径上每一条边,跑最短路记录最大值。 适用条件:非严格 简单
- 3.从起点s和终点t分别跑出最短路d1,d2,枚举图中每一条边<u,v>,计算(d1[u]+d2[v]+边权)的次大值。
适用条件:严格/非严格 非简单
例题:
1.P1491 集合位置 (非严格|简单)
2.P2865 Roadblocks G (严格|非简单)
10.22
k短路
- 1.A*算法:从终点t跑出最短路h(i),跑bfs,队列元素按照h(i)+g(i)从小到大排序(g(i)指s到i的实际路径长度)。
适用条件:非严格 非简单 时间复杂度:O(nklogn)
改进:可用数组v存下路径,判断新节点是否已在路径上,即可实现求简单路径。(时间复杂度难以保证) - 2.可持久化可并堆
不会
例题:[SDOI2010] 魔法猪学院
[SCOI2007] k短路
10.23-10.24
字符串哈希
进制数:131 13331 9973
一.一维哈希
1.自然溢出法:用ULL类型存储hash值。(速度快,但易被卡) 2.多模哈希:用多个模数分别去模,判断时需hash值皆相等。
常用模数:1e9+21 1e9+223(速度慢,很难被卡)
3.大质数哈希:用1e18级别的模数取模
常用模数:1e18+31
字符串哈希
POJ3974 Palindrome (哈希+二分)
二.二维哈希
方法:先每一行进行hash,再将hash后的值在列方向上看成新的字符串进行一遍hash,最后询问时用二维前缀和公式解决。(两边hash要用不同进制数)
例题:POJ3690星座(极其恶心的一道毒瘤题,卡常卡空间)
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
int n, m, t, p, q, cnt = 1;
ull hs[1005][1005];
ull hst[55][55];
int P1 = 131, P2 = 13331;
ull p1[1005], p2[1005];
multiset<ull>app;
int main()
{
p1[0] = p2[0] = 1;
for(int i = 1; i <= 1001; ++i)
p1[i] = p1[i-1]*P1;
for(int i = 1; i <= 1001; ++i)
p2[i] = p2[i-1]*P2;
while(scanf("%d%d%d%d%d", &n, &m, &t, &p, &q))
{
app.clear();
if(n == 0 && m == 0 && t == 0 && p == 0 && q == 0)
break;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
char ch = getchar();
while(ch==' '||ch=='\n')ch=getchar();
hs[i][j] = hs[i][j-1]*P1+(int)ch;
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
hs[i][j] += hs[i-1][j]*P2;
for(int i = 1; i <= t; ++i)
{
for(int j = 1; j <= p; ++j)
for(int k = 1; k <= q; ++k)
{
char ch = getchar();
while(ch==' '||ch=='\n')ch=getchar();
hst[j][k] = hst[j][k-1]*P1+(int)ch;
}
for(int j = 1; j <= p; ++j)
for(int k = 1; k <= q; ++k)
hst[j][k] += hst[j-1][k]*P2;
app.insert(hst[p][q]);
}
for(int i = 1; i <= n-p+1; ++i)
for(int j = 1; j <= m-q+1; ++j)
{
ull tmp = hs[i+p-1][j+q-1]-hs[i-1][j+q-1]*p2[p]-hs[i+p-1][j-1]*p1[q]+hs[i-1][j-1]*p1[q]*p2[p];
app.erase(tmp);
}
printf("Case %d: %d\n", cnt, t-(int)app.size());
cnt++;
}
return 0;
}
10.25
树状数组
用途:维护序列的前缀和。
实现方法:对于一个长为n的序列,使c[i]存储序列区间[i-lowbit(i)+1,i]中所有数的和。
时间复杂度:O(nlogn)
问题1:P3374 【模板】树状数组 1
单点修改,将数组c中每个包含a[i]的元素修改。
区间查询,求出r和l-1的前缀和取差。
问题2:P3368 【模板】树状数组 2
将c数组初始赋为0,c的前缀和代表第i个位置上加的数的和。
区间修改,将c[l]加上k,c[r+1]减去k。
单点查询,输出a[i]+c[i]的前缀和。
问题3:P3372 【模板】线段树 1
数组c[i]的前缀和代表i增加的量,则1-x整体增加量
为: sigma(i=1-x)sigma(j=1-i)c[j]。
可将上式改写为:(x+1)×sigma(i=1-x)c[i]-sigma(i=1-x)i×c[i]。 我们用树状数组维护c[i]和c[i]*i的前缀和即可解决。
问题4:求逆序对个数
我们用数组c[i]记录值i出现的次数,用树状数组维护c的前缀和。倒序扫描序列,查询值1——a[i]-1的出现总次数,将其加入答案中。再将c[a[i]]加上1。
例题:P10589 楼兰图腾
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】