2019.8.6前,学习记录

cin所需时间是scanf所需时间的3倍

spfa算法:
求解负边权的单源最短路算法,如果在正权图上应使用效率更高的Dijkstra算法。
我们约定加权有向图G不存在负权回路,即最短路径一定存在。用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
定理:只要最短路径存在,上述SPFA算法必定能求出最小值。证明:每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点v的最短路径估计值d[v]变小。所以算法的执行会使d越来越小。由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的逐渐变小,直到到达最短路径值时,算法结束,这时的最短路径估计值就是对应结点的最短路径值。
如果
判断是否存在负权回路,定义数组记录该点遍历过几次,如果超过n,即存在负权回路,原理:存在负环的节点会重复入队(因为最短路在不断变小)

void spfa()
{
queueque;
for(int i = 1; i <= n; i++)
dis[i] = INF;//初值记得赋无穷,而不是G数组中的值!
dis[1] = 0;
vis[1] = true;
que.push(1);
while(!que.empty())
{
int now = que.front();
que.pop();
vis[now] = false;//记得还原!!
for(int i = 1; i <= n; i++)
{
if(dis[now]+G[now][i]<dis[i])
{
dis[i] = dis[now]+G[now][i];
if(!vis[i])
{
vis[i] = true;
que.push(i);
}
}
}
}
printf("%d\n", dis[n]);
}

Dijkstra算法。
若给定的图存在负权边,类似Dijkstra算法等算法不可用
建立标记数组,
建立起始数组vis,要求点到个点距离
遍历vis找到最近且未标记点
标记该点
以该点为放缩点,找未标记的点,求最短距离
void dj()
{
memset(flag,0,sizeof(flag));
for (int i=1; i<=n; i++)
d[i]=tu[1][i];
flag[1]=1;
for(int i=1; i<=n-1; i++)
{
int x,u;
x=INF;
for(int j=1; j<=n; j++)
{
if(!flag[j]&&d[j]<x)
{
x=d[j];
u=j;
}
}
flag[u]=1;
for(int j=1; j<=n; j++)
{
if(d[j]>d[u]+tu[u][j]&&!flag[j])
d[j]=d[u]+tu[u][j];
}
}
cout<<d[n]<<endl;
}

manacher算法:
确定回文中心,以及确定回文半径
int MANACHER(char st,int len)
{
int mx=0,ans=0,po=0;//mx即为当前计算回文串最右边字符的最大值,po当前回文中心
for(int i=1;i<=len;i++)
{
if(mx>i)
Len[i]=min(mx-i,Len[2
po-i]);//在Len[j]和mx-i中取个小
//回文半径大于i值
else
Len[i]=1;//如果i>=mx,要从头开始匹配
while(st[i-Len[i]]==st[i+Len[i]])
Len[i]++;//更新i的回文半径
if(Len[i]+i>mx)//若新计算的回文串右端点位置大于mx,要更新po和mx的值
{
mx=Len[i]+i;
po=i;
//更新当前最大回文半径
}
ans=max(ans,Len[i]);
}
return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
}

最小表示法(最大表示法)
最小表示法是求与某个字符串循环同构的所有字符串中,字典序最小的串是哪个。
设i、j是两个“怀疑是最小的位置”,比如说如果你比较到了jdrakioi的两个i,你目前还不知道从哪个i开始的字符串是最小的。
设k表示,从i往后数和从j往后数,有多少是相同的。
开始时先设i=0,j=1,k=0。
每次都对i+k、j+k进行一次比较。
比较完i+k和j+k,如果两个字符相等,那么显然k++。
如果不相等,那么哪边比较大,哪边就肯定不是最小的了,同时把k重置为0。
如果出现了i、j重合的情况,把j往后移动一位。
最后输出i、j较小的那个就好了。

树:空树也是树,节点数减一为边数

priority_queue <int,vector,less > p;
.
.
priority_queue <int,vector,greater > q;
less:14 12 10 8 6 
greater:6 8 10 12 14
如果使用优先队列结构体必须有结构体类型cmp
priority_queue<node,vector,cmp1> q1;
struct node
{
int fir,sec;
}input;

struct cmp1
{
bool operator () (const node &x,const node &y) const
{
return x.fir<y.fir;
}
};//当一个node x的fir值小于另一个node y的fir值时,称x<y
q.size();//返回q里元素个数
q.empty();//返回q是否为空,空则返回1,否则返回0
q.push(k);//在q的末尾插入k
q.pop();//删掉q的第一个元素
q.top();//返回q的第一个元素

查找一个数在一个数组中的某一段区间出现过几次方法
1.建立二维victor,输入的数组元素为行坐标,该元素在数组中位置为列坐标,
2.当查询在L到R出现几次x时
使用lower_bound(a,a+n,L)查询在victor中第x行的元素值大于等于L的下标,再upper_bound(a,a+n,R)查询在victor中第x行的元素值大于R的下标,两数相减,即一个数在一个数组中的某一段区间出现过几次方法

1.std::ios::sync_with_stdio(false);
百度了一下,原来而cin,cout之所以效率低,是因为先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间,使效率与scanf与printf相差无几,还有应注意的是scanf与printf使用的头文件应是stdio.h而不是iostream。
1.    std::ios::sync_with_stdio(false);
2.    std::cin.tie(0);

Map<string,int>p
P[string]=i;
A=i;
例如:lin zhou song bin
0 1 2 3
即如果输入zhou即等于输入1

C++ STL中的binary_search(二分查找)
前提已经排序

1.头文件

#include

2.功能

在数组中查找某个元素是否存在

函数模板:binary_search(arr[],arr[]+size,index)

参数说明:arr[]:数组首地址

size:数组元素个数

index:需要查找的元素
.
while(next_permutation(str.begin(),str.end()))
cout<<str<<endl;
.全排列函数
.

费马小定理:a^(p-1)%p=1,且a与p互质;
数据如果给的是1e9之类的一定是规律题目
next数组可以求最小循环节长度,比如打表找出其中最小循环,len-next[len],len表的长度
判断一个数是否取余20,只判断最后一位即可
判断一个数是否取余3
0,判断各位数字之和取余是3否为0即可
判断一个数是否取余90,判断各位数字之和取余是9否为0即可
判断一个数是否取余4
0,只判断这个数最后两位取余4是否为0即可
判断一个数是否取余110,判断这个数偶数位数字之和与奇数位数字之和的差取余11是否为0即可
同时能被11,7,13整除的数的特征,这三个数的末三位与末三位以前的数字组成的数之差能被7,11,13整除
线性筛法是指
第一个循环第一个数与第二个数之间差的循环递增
第二个循环
第一个数与第一个与第一个成倍数的数的倍数的递增循环
gcd(x,y)=gcd(x,y-x);
gcd优化:
若x,y均为偶数,则gcd(x,y)=2gcd(x/2,y/2);
若x为奇数,y为偶数gcd(x,y)=gcd(x,y/2);
若x为偶数,y为奇数gcd(x,y)=gcd(x/2,y);
若x,y均为奇数gcd(x,y)=gcd(x-y,y);
lcm(x,y)=x
y/gcd(x,y);
扩展欧几里得算法:
ax+by=m,且m%gcd(a,b)=0;
不断对a,b进行gcd运算,直到b
0,使x=1,y=0,m=gcd(a,b),此时a=gcd(a,b),b=0;
递归回去求的x,y
举例50 120
运算过程
a b x y gcd(a,b)
120 50 _ _ _
50 120 _ _ _
50 20 _ _ _
20 10 _ _ _
10 0 1 0 10
20 10 0 1 10
50 20 1 -2 10
120 50 -2 5 10
50 120 5 -1 10
求解二元一次方程ax+by=m的一组解
即先求ax+by=gcd(a,b),的一组解x0,y0
所以ax+by=m的一组解为x=m/gcd(a,b)x0
y=m/gcd(a,b)y0;
32=2(mod5)
逆元…
下列矩阵旋转180°
3 4 5 5 6 7 7 6 5
4 5 6 4 5 6 6 5 4
5 6 7 3 4 5 5 4 3
所以对应位置相加得
10 10 10
10 10 10
10 10 10
可得
矩阵所有元素求和,若矩阵元素之间有一定规律可先将矩阵旋转180°
判断旋转后矩阵与原矩阵对应位置相加求的另一个矩阵,若另一个矩阵所有元素相等则该矩阵元素求和等于
矩阵首元素加矩阵末元素的和乘以矩阵规模再除以2
中国剩余定理
三三取余二,五五取余三,七七取余二,求最小的此数
xx取余a,yy取余b,zz取余c,
dxz+exy+fyz=k,dxz%y=0,exy%z=0,fyz%x=0;
所以所求数为k%xyz;
斐波那契额数列
|f0 n=0
F(n)=|f1 n=1
|a
f(n-1)+b
f(n-2)
设k,m;
k=(a+(a2+4*b)(1/2))/2,m=(a-(a2+4*b)(1/2))/2,
F(n)=((kn)*(f(1)-m*f(0))-(mn)(f(1)-kf(0)))/(k-m)
给定一个数num.和一个数组a[],在空间复杂度为O(1),时间复杂度为O(n)下,使小于num的在数组左边,大于num的再数组右边
等于的放中间
建立两个指针,一个记录从[0,x]小于num在数组中的范围,一个记录从[0,y]小于等于num在数组中的范围,如果遇到相等于num
的值,此值于y+1交换并y++,如果遇到小于num的值,此值于x+1,交换并x++,然后此值于y+1交换并y++,
KMP算法中next数组的意义是该位置之前的子序列的前缀等于后缀的长度
给定一个串abcabc问最少添加几个字符构成的新串含两个原子串abcabcabc
求法令x=len-next[len],取最后x位添加到串最后即可
看了看别人的题解,都是枚举小于n的完全平方数输出,代码极为简单,因此本人不再给出代码。

给定以上两个树a,b;
如何证明树b出现在树a里面
将树a,树B 先序遍历,再kmp求解
BFPRT…不学

建立一个窗口,然后逐一从右边进入,如果比右边小直接进入,否则将右边的一项弹出,再判断直到符合为止,若全不符合,则全部清除,运算时注意窗口大小

建立两个以上的窗口max,min窗口,如果max-min<=num且范围从L到R,则L到R全部符合,
故从0开始运算L指针不动,R指针向右直到不成立为止,然后sum+=R-L;下来弹出0位置的相关信息,从1位置继续以上运算,运算时L和R指针不回退
单调栈:

求一个数左边最近比他大的,以及右边最近比他大的
建立一个从大到小的栈,如果为空直接进栈,如果比栈顶大直接进栈,如果比栈顶小,栈顶弹出元素,弹出的元素右边最近比他大的就是现在未入栈的元素,左边最近比他的就是弹出元素后的栈顶元素

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值