常见数据结构/算法模板


title: 常见数据结构/算法模板
date: 2020-08-20
categories: acm
tags: acm
top: true

0. to start with

remembering one trick is better than recording a hundred.

包含一些模板和例题

技巧,STL,函数,细节,参考资料(比如背包九讲)等见 https://www.cnblogs.com/lqerio/p/13484897.html

1. DP Dynamic Programming

如果前面的结果可以被利用,就可以dp。
先写状态转移方程,边界条件,初始结束状态的设置。
如果数据计算量大可以预处理。

woj1023.
dp 状态转移方程: f[i]=min(f[i],f[j]+valuecluser[j+1][i])(i-j>=p)  //j+1...注意分界点 dp[0]=0.i in range p-1-N (编号为1-n)
//dp注意初始状态结束状态预处理。f[0]=0,f[i]初始为maxd
预处理:计算valuecluster[i][j]

1.1 Pack 背包

1.1.1 01背包

WOJ1005
const int maxn=10005;
int value[maxn];
int sizee[maxn];
int final[100005];
for(int i=0;i<=noah;i++) final[i]=0;  
    for(int i=0;i<n;i++)
        for(int j=noah;j>0;j--)   //倒序理解就是01背包只有一件,前i-1件已经判断完了,只判断这一件,在比较小的情况下放不影响在比较大的情况放
            if(j>=sizee[i])         //final可行因为如果小的能放大的也能放。
                final[j]=max(final[j],final[j-sizee[i]]+value[i]);
        cout<<final[noah]<<endl;
    }

1.2 剪枝 / 回溯

还是待更新!!!!
下面的不全

剪枝
1.最优化剪枝:如果当前已经找到的最优路径长度为L ,那么在继续搜索的过程中,总长度已经大于等于L的走法,就可以直接放弃,不用走到底了

2.可行性剪枝:如果当前到达城市的路费已大于k,或者等于k且没有到达终点,就可以直接放弃。

回溯

used[i] = 1;//设为用过 
            dfs(u + 1);//下一个数字 
            used[i] = 0;//回溯:回到没用过 
			

1.3 方格&&滚动数组&&优化时间

见我的woj1012题解

2. DFS

2.1 recursive

PAT 1004
#include<iostream>
#include<queue>
#include<vector>

using namespace std;
vector<int>nodes[100];
int ans[105];
int level;
void dfs(int id,int depth){
    level=max(level,depth);
    int temp=id;
        if(nodes[temp].size()==0){
            ans[depth]++;
        }
        else{
            for(int i=0;i<nodes[temp].size();i++){
                dfs(nodes[temp][i],depth+1);
            }
        }
}

int main(){
    int n,m;
    cin>>n>>m;
    int father,num,son;
    for(int i=0;i<m;i++){
        cin>>father>>num;
        for(int j=0;j<num;j++){
            cin>>son;
            nodes[father].push_back(son); // at first i write push_back[]
        }
    }
    level=1;
    dfs(1,level);
    cout<<ans[1];
    for(int i=2;i<=level;i++) //at first i write push_back[] < but not <=
        cout<<' '<<ans[i];
        system("pause");
    return 0;
}

2.2 stack

找到与最先出发点的所有邻接点,将他们入栈,
标记这些点已经访问过,后面和bfs的队列实现有点像。
UVA280

#include<bits/stdc++.h>
using namespace std;
const int maxn=150;
int node_num,st,ed,stnodenum,stnode,vis[maxn];
 
void dfs(int stnode,vector<int> v[]){
    memset(vis,0,sizeof(vis));
    stack<int> s;
    vector<int> t;
    for(int i=0;i<v[stnode].size();i++){
        int temp=v[stnode][i];
        if(!vis[temp]){
            s.push(temp);
            vis[temp]=1;
        }
    }
    while(!s.empty()){
        int ans=s.top();
        s.pop();
        for(int i=0;i<v[ans].size();i++){
            int temp=v[ans][i];
            if(!vis[temp]){
                s.push(temp);
                vis[temp]=1;
            }
        }
    }
    for(int i=1;i<=node_num;i++){
        if(!vis[i])
        t.push_back(i);
    }
    cout<<t.size();
    for(int i=0;i<t.size();i++)
        cout<<" "<<t[i];
    cout<<endl;
}
 
int main(){
    while(scanf("%d",&node_num)!=EOF){
        if(node_num==0) break;
        vector<int> v[maxn];
        for(;;){
            scanf("%d",&st);
            if(!st)
                break;
            for(;;){
                scanf("%d",&ed);
                if(!ed)
                    break;
                v[st].push_back(ed);
            }
        }
        scanf("%d",&stnodenum);
        for(int i=0;i<stnodenum;i++){
            scanf("%d",&stnode);
            dfs(stnode,v);
        }
    }
    return 0;

3. BFS

3.1 QUEUE

PAT 1004
#include<iostream>
#include<queue>
#include<vector>

using namespace std;
vector<int>nodes[100];
int ans[105];
int depth[105];
int level;
void bfs(int id){
    queue<int>q;
    q.push(id);
    while(!q.empty()){
        int temp=q.front(); //at first i write "top()"
        q.pop();
        level=max(level,depth[temp]);
        if(nodes[temp].size()==0){
            ans[depth[temp]]++;
        }
        else{
            for(int i=0;i<nodes[temp].size();i++){
                depth[nodes[temp][i]]=depth[temp]+1;
                q.push(nodes[temp][i]);
            }
        }
        
    }
}

int main(){
    int n,m;
    cin>>n>>m;
    int father,num,son;
    for(int i=0;i<m;i++){
        cin>>father>>num;
        for(int j=0;j<num;j++){
            cin>>son;
            nodes[father].push_back(son); // at first i write push_back[]
        }
    }
    depth[1]=1;
    level=1;
    bfs(1);
    cout<<ans[1];
    for(int i=2;i<=level;i++) //at first i write push_back[] < but not <=
        cout<<' '<<ans[i];
        system("pause");
    return 0;
}

3.2 recursion

void BFS(int st) {
	int len = G[st].size();
	for (int i = 0 ; i < len ; i ++ ) {
		que.push(G[st][i]);
	}
	if ( !que.empty() ) {
		int top = que.front() ; que.pop() ;
		printf("%d ",top) ;
		BFS(top) ;
	}

4. topo 拓扑排序

//拓扑排序可以判断有向图有没有环。
//dfs判断图联通。

5. math

5.1 euler path /circuit

https://www.cnblogs.com/wkfvawl/p/9626163.html

DFS Fleury(佛罗莱)算法求解

5.2 Huffman Coding 哈夫曼编码

6. GRAPH 图

6.1 Red Black Tree

6.2 AVL

6.3 tree traversal 树的遍历

https://www.cnblogs.com/qjmnong/p/9135386.html

Pre-order

recursive

void pre_order(TreeNode * Node)
{
if(Node == NULL)
return;
printf("%d ", Node->data);
pre_order(Node->left);
pre_order(Node->right);
}

Iteration

class TreeNode {
	public int val;
	public TreeNode left, right;

	public TreeNode(int val) {
		this.val = val;
		this.left = this.right = null;
	}
}

先push(root)
node = pop()
loop:
list.add( node.val )
push( node.right )
push( node.left )
循环步骤直到栈空

public List<Integer> preorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();
		s.push(root);

		while (!s.isEmpty()) {
			
			TreeNode node = s.pop();
			list.add(node.val);
			
			if (node.right != null) {
				s.push(node.right);
			}
			
			if (node.left != null) {
				s.push(node.left);
			}
		}
		
		return list;
	}

Middle-order

recursive

void middle_order(TreeNode *Node)//中序遍历递归算法
{
    if(Node == NULL)
        return;
    middle_order(Node->left);
    printf("%d ", Node->data);//在中间
    middle_order(Node->right);
}

Iteration

把root、以及root左孩子都压入栈中
loop:
node = pop()
list.add( node.val )
root = node.right
循环步骤直到栈为空且root为null

public static List<Integer> inorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();

		do {
			while (root != null) {
				s.push(root);
				root = root.left;
			}
			if (!s.isEmpty()) {
				TreeNode node = s.pop();
				list.add(node.val);
				root = node.right;
			}
		} while (!s.isEmpty() || root != null);

		return list;
	}

Post-order

recursive

void post_order(TreeNode *Node)//后序遍历递归算法
{
    if(Node == NULL)
        return; 
    post_order(Node->left);
    post_order(Node->right);
    printf("%d ", Node->data);//在最后
}

Iteration

先push(root)
loop:
node = pop()
list.add( 0 , node.val )
push( node.left )
push( node.right )
循环步骤3直到栈空
之后倒序遍历list

public static List<Integer> postorderTraversal(TreeNode root) {
		if (root == null) {
			return null;
		}
		List<Integer> list = new ArrayList<Integer>();

		Stack<TreeNode> s = new Stack<TreeNode>();
		
		s.push(root);
		
		while( !s.isEmpty() ) {
			TreeNode node = s.pop();
			if(node.left != null) {
				s.push(node.left);
			}
			
			if(node.right != null) {
				s.push(node.right);
			}
			
			list.add(0, node.val);
		}
		
		return list;
	}

6.4 BST (binary search tree)

https://www.cnblogs.com/lqerio/p/11901828.html

6.5 最短路

https://blog.csdn.net/strve/article/details/80957491
Floyed +Dijkstra + Bellman-Ford + SPFA (SPFA就是队列优化版的BF)。
///BF 适用于含有负边的图。如果有负边,返回false。Dijkstra算法无法判断含负权边的图的最短路.二者都适用于有向有环图。
//拓扑排序可以判断有向图有没有环。
//dfs判断图联通。

6.5.1 dijkstra

PAT 1003 为例

模板 Dijkstra+链式前向星+堆优化

https://www.cnblogs.com/zmin/p/7349100.html

matrix O() 邻接矩阵版

#include<bits/stdc++.h>
using namespace std;
int graph[505][505];//图
int city[505],dis[505],pathNum[505],teamNum[505];//每个城市救护队的数量、到达每个城市的最短距离、到达每个城市的最短路径的数量、到达每个城市的救护队数量
bool visit[505];//每个城市是否被访问过
int N,M,C1,C2;
void Dijkstra(){
    while(!visit[C2]){//如果终点城市还没有被访问,继续循环
        int MIN=INT_MAX,v=-1;//找出目前距离最短的还没有被访问的城市
        for(int i=0;i<N;++i)
            if(!visit[i]&&MIN>dis[i]){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//标记为已访问
        for(int i=0;i<N;++i)
            if(!visit[i]&&graph[v][i]!=0&&dis[v]+graph[v][i]<dis[i]){
                dis[i]=dis[v]+graph[v][i];//更新最短路径长度
                pathNum[i]=pathNum[v];//更新最短路径数量
                teamNum[i]=teamNum[v]+city[i];//更新城市的救护队数量
            }else if(graph[v][i]!=0&&dis[v]+graph[v][i]==dis[i]){
                pathNum[i]+=pathNum[v];//增加最短路径数量
                teamNum[i]=max(teamNum[i],teamNum[v]+city[i]);//找出能够召集最多的城市救护队数量
            }
    }
}
int main(){
    scanf("%d%d%d%d",&N,&M,&C1,&C2);
    for(int i=0;i<N;++i)
        scanf("%d",&city[i]);
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a][b]=c;
        graph[b][a]=c;
    }
    fill(dis,dis+N,INT_MAX);//将最短路径均设置为最大值
    dis[C1]=0;//C1城市是起点,最短路径为0
    teamNum[C1]=city[C1];//C1城市是起点,最短路径数量为1
    pathNum[C1]=1;//C1城市是起点,能够召集的救护队数量为本城市的数量
    Dijkstra();
    printf("%d %d",pathNum[C2],teamNum[C2]);//输出
    return 0;
}

邻接表版

#include<bits/stdc++.h>
using namespace std;
struct Road{
    int v;//道路尽头的城市编号
    int length;//道路长度
    Road(int vv=0,int l=0):v(vv),length(l){}
};
vector<vector<Road>>graph(505);//图
int city[505],dis[505],pathNum[505],teamNum[505];//每个城市救护队的数量、到达每个城市的最短距离、到达每个城市的最短路径的数量、到达每个城市的救护队数量
bool visit[505];//每个城市是否被访问过
int N,M,C1,C2;
void Dijkstra(){
    while(!visit[C2]){//如果终点城市还没有被访问,继续循环
        int MIN=INT_MAX,v=-1;//找出目前距离最短的还没有被访问的城市
        for(int i=0;i<N;++i)
            if(!visit[i]&&dis[i]<MIN){
                MIN=dis[i];
                v=i;
            }
        visit[v]=true;//标记为已访问
        for(Road r:graph[v]){
            if(!visit[r.v]&&dis[r.v]>dis[v]+r.length){
                dis[r.v]=dis[v]+r.length;//更新最短路径长度
                pathNum[r.v]=pathNum[v];//更新最短路径数量
                teamNum[r.v]=teamNum[v]+city[r.v];//更新城市的救护队数量
            }else if(dis[r.v]==dis[v]+r.length){
                pathNum[r.v]+=pathNum[v];//增加最短路径数量
                teamNum[r.v]=max(teamNum[r.v],teamNum[v]+city[r.v]);//找出能够召集最多的城市救护队数量
            }
        }
    }
}
int main(){
    scanf("%d%d%d%d",&N,&M,&C1,&C2);
    for(int i=0;i<N;++i)
        scanf("%d",&city[i]);
    while(M--){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        graph[a].push_back(Road(b,c));
        graph[b].push_back(Road(a,c));
    }
    fill(dis,dis+N,INT_MAX);//将最短路径均设置为最大值
    dis[C1]=0;//C1城市是起点,最短路径为0
    pathNum[C1]=1;//C1城市是起点,最短路径数量为1
    teamNum[C1]=city[C1];//C1城市是起点,能够召集的救护队数量为本城市的数量
    Dijkstra();
    printf("%d %d",pathNum[C2],teamNum[C2]);//输出
    return 0;
}

priority_queue lrj版

设m edges,n vertexs
复杂度 mlog(n)
算法中 ** while(!Q.empty()){} ** 部分使得每个边都被遍历到,m。而优先队列插入复杂度为log(n).故整体mlog(n)
注意m可能大于n^2 最后复杂的>n^2.但不常见

PAT 1003

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include<vector>

using namespace std;
const int maxn = 505 + 5; //vertexs
const int INF = 99999999;

int city[505];
int pathnum[505],teamnum[505];

struct Edge
{
    int from,to,dist;
    Edge(int f=0,int t=0,int d=0):from(f),to(t),dist(d){}
};
struct HeapNode//优先队列节点
{
    int d,u;
    HeapNode(int _d=0,int _u=0):d(_d),u(_u){}
    bool operator<(const HeapNode &rhs)const
    {
        return d>rhs.d;
    }
};
struct Dijkstra  //边权为正 负权存在用Bellman-Ford 每两点间最短路floyd
{
    int n,m;               //点数和边数  O(mlog n)
    vector<Edge> edges;    //边列表
    vector<int> G[maxn];   //每个节点出发的边编号(编号从0开始)
    bool done[maxn];       //是否已永久标号
    int d[maxn];           //s到各个点的距离
    int p[maxn];           //最短路中的上一条边
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n;i++)G[i].clear();
        edges.clear();
    }
    void AddEdge(int from,int to,int dist)
    {
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from].push_back(m-1);
        
                edges.push_back(Edge(to,from,dist)); //无向图,双向
        m=edges.size();
        G[to].push_back(m-1);
    }

    void dijkstra(int s)   //s start
    {
        priority_queue<HeapNode> Q;   //优先队列,d[i]越小越先出队
        for(int i=0;i<n;i++)d[i]=INF;
        d[s]=0;
        memset(done,0,sizeof(done));
        Q.push(HeapNode(0,s));
        while(!Q.empty()) //第一轮将s能到的点都压入队列,之后每次取d[i]最小的点先出(优先队列)
        {
            HeapNode x=Q.top();Q.pop();
            int u=x.u;                     //u 当前处理点编号
            if(done[u])continue;
            done[u]=true;
            for(int i=0;i<G[u].size();i++)
            {
                Edge &e=edges[G[u][i]];
                if(d[e.to]>d[u]+e.dist)
                {
                    d[e.to]=d[u]+e.dist; //d[u],出发点s到u的距离
                    p[e.to]=G[u][i];     //到达e.to点的边为G[u][i]
                    Q.push(HeapNode(d[e.to],e.to));
                        pathnum[e.to]=pathnum[e.from];
                        teamnum[e.to]=city[e.to]+teamnum[e.from];
                }
                else if(d[e.to]==d[u]+e.dist){
                         pathnum[e.to]+=pathnum[e.from];
                        teamnum[e.to]=max(city[e.to]+teamnum[e.from],teamnum[e.to]);
                }
            }
        }
    }
};

int main()
{
    Dijkstra dijk;
    int n,m,start,end;                 //n number of vertex m number of edges
    cin>>n>>m>>start>>end;
    for(int i=0;i<n;i++)
        cin>>city[i];
        dijk.init(n);
        int from,to,dist;
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d",&from,&to,&dist);
            dijk.AddEdge(from,to,dist);
        }
    pathnum[start]=1;
    teamnum[start]=city[start];
    dijk.dijkstra(start);
    cout<<pathnum[end]<<' '<<teamnum[end];
    
    return 0;
}

6.5.2 SPFA

woj1009

// woj1009

#define INF 0x3f3f3f3f


char word[4005];
int plovers,slovers;
int n, m,edgenum;
const int maxn=105;  //const    点的数

struct Edge {
int from, to, power,speed,dist;
char word;
Edge(int u, int v,int p,int s, int d,char word):from(u),to(v),power(p),speed(s),dist(d),word(word){}
};

vector<Edge> edges;
vector<int> G[maxn];
bool inq[maxn]; //是否在队列里
int d[maxn]; //s到各个点的距离
int p[maxn]; //最短路中的上一条弧
int cnt[maxn]; //入队次数 次数大于n则说明有负环

void init(int n) {
edgenum=0;
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}

void AddEdge(int from, int to, int power,int speed,int dist,char word) {
edges.push_back(Edge(from, to, power,speed,dist,word));
edgenum = edges.size();           //错误,一开始写成m,而m又是全局变量导致下面data()的循环除了问题
G[from].push_back(edgenum-1);  //边的标号
}

//拓扑排序可以判断有向图有没有环
//dfs判断图联通

bool bellman_ford(int s) {  ///BF 适用于含有负边的图。如果有负边,返回false。Dijkstra算法无法判断含负权边的图的最短路.二者都适用于有向有环图
    queue<int> Q;
    memset(inq, 0, sizeof(inq));
    memset(cnt, 0, sizeof(cnt));
    for(int i = 0; i < n; i++) d[i] = INF;
    d[s] = 0;
    inq[s] = true;
    p[s]=-1;     //加了一条
    Q.push(s);
    while(!Q.empty()) {
        int u = Q.front(); Q.pop();
        inq[u] = false;
        for(int i = 0; i < G[u].size(); i++) {
            Edge& e = edges[G[u][i]];
                if(d[u] < INF && d[e.to] > d[u] + e.dist&&plovers>e.power&&slovers>e.speed) {    //模板,+条件
                    d[e.to] = d[u] + e.dist;
                    p[e.to] = G[u][i];
                    if(!inq[e.to]) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to] > n) return false;}
                }
        }
    }
    vector<char>ans;  //也可以写一个函数递归,没必要
    int tmp=p[n-1];
    while(tmp!=-1){
        ans.push_back(edges[tmp].word);
        tmp=p[edges[tmp].from];
    }
    for(int i=ans.size()-1;i>-1;i--)
        cout<<ans[i];
    cout<<endl;
    return true;
}


void data(){
    init(n);
    int from,to,power,speed,dist,tmp;
    char word;
    for(int i=0;i<m;i++){
        /*  这样写有问题。读了空格
           scanf("%d%d%d%d%d",&from,&to,&power,&speed,&dist);
           scanf("%c",&word);
           */
          /*
          scanf("%d%d%d%d%d",&from,&to,&power,&speed,&dist);
           getchar();scanf("%c",&word);getchar();*/     //处理最后一个字符前的空格这样可以,但是麻烦
           scanf("%d %d %d %d %d %c",&from,&to,&power,&speed,&dist,&word);  //注意%c不是%s 。也可以fstream
           AddEdge(from,to,power,speed,dist,word);
           }
    cin>>plovers>>slovers;
    bellman_ford(0);
}


6.6 生成树

6.7 如何建图?

邻接矩阵  //数据范围很大,不能用邻接矩阵

邻接表

邻接表可以用 链表或者 vector 见 woj1006

vector<int>mapp;
for(int i=0;i<n;i++)
            mapp[i].clear();
        for(int i=0;i<m;i++){
            scanf("%d%d", &x, &y);  mapp[x].push_back(y);  mapp[y].push_back(x);
        }


紫书模板建图 见我的题解 woj1009


一般的用vector[i]表示i所连边 见我的题解 woj1024

7. Sort

https://www.cnblogs.com/lqerio/p/13484897.html

8. greedy 贪心

https://www.cnblogs.com/lqerio/p/11749926.html

9. 字符串 string

9.1 KMP

9.2 AC 自动机

9.3 字典序 Dictionary order

https://www.cnblogs.com/lqerio/p/11785894.html

sort,strcmp,string

woj1013
字典序全排列生成:https://www.cnblogs.com/lqerio/p/12079873.html

比较可以用sort(qsort不推荐)
bool cmp(char*a,char*b){
    return strcmp(a,b);
}

bool cmp1(string a,string b){
    return a<b;
}
vector<string>ans;
sort(ans.begin(),ans.end(),cmp1);

9.4 leetcode5 Manacher法 最长回文字符串

https://www.cnblogs.com/lqerio/p/11723652.html

10. 网络流

见woj1008.

11. kth biggest/smallest

https://www.cnblogs.com/lqerio/p/9757284.html

12. others

12.1 make an structure of O(1) search,insert,delete

leetcode381

12.2 GCD

    int gcd(int a,int b)
    {
       // return (b==0)?gcd(b,a%b):a
         if(b==0)
              return a;
         else
              return gcd(b,a%b);
    }

12.3 Prime

bool isPrime(int n) {

	if (n < 2)
		return false;
   int m=sqrt(n+0.5);
	for (int i = 2; i <= m; i++) {

		if (n % i == 0)
			return false;
	}

	return true;
}

void euler_sieve(int n)  //线性筛
{
    totPrimes = 0;
    memset(flag, 0, sizeof(flag));

    for (int i = 2; i <= n; i++) {
        if (!flag[i])
            primes[totPrimes++] = i;
        for (int j = 0; i * primes[j] <= n; j++) {
            flag[i*primes[j]] = true;
            if (i % primes[j] == 0)
                break;
        }
    }
}

void eratosthenes_sieve(int n)
{
    totPrimes = 0;
    memset(flag, 0, sizeof(flag));

    int sqrtn = sqrt(n + 0.5);
    for (int i = 2; i <= sqrtn; i++) {
        if (!flag[i]) {
            primes[totPrimes++] = i;
            for (int j = i * i; j <= n; j += i) {
                flag[j] = true;
            }
        }
    }
    for (int i = sqrtn + 1; i <= n; i++) {
        if (!flag[i])
            primes[++totPrimes] = i;
    }
}
int binarysearch(int x)
{
    int l=0,r=n*n;
    while(r-l>=1)
    {
        int i=(r+l)/2;
        if(num[i]==x) return 1;
        else if(num[i]<x) l=i+1;
        else r=i;
    }
    return 0;
}

12.5 pow

ll pow(ll a,ll n) //a^n
{
    ll result=1,flag=a;
    while(n!=0)
    {
        if(n&1)
            result=result*flag;
        flag=flag*flag;
        n=n>>1;
    }
    return result;
}

ll pow(ll a,ll n,ll b) //a^n %b  to avoid Integer overflow
{
    ll result=1;
    a=a%b;
    while(n>0)
    {
        if(n%2==1)
            result=result*a%b;
        n=n/2;
        a=a*a%b;
    }
    return result;
}

12.6 floating numbers

uva11809
https://blog.csdn.net/crazysillynerd/article/details/43339157


#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
 
using namespace std;
 
int main() {
    double M[20][40];
    long long E[20][40];
 
    // 打表
    for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
        double m = 1 - pow(2, -1 - i), e = pow(2, j) - 1;
        double t = log10(m) + e * log10(2);
        E[i][j] = t, M[i][j] = pow(10, t - E[i][j]);
    }
 
    // 输入并输出结果
    string in;
    while(cin >> in && in != "0e0") {
        // 处理输入
        for(string::iterator i = in.begin(); i != in.end(); ++i) if(*i == 'e') *i = ' ';
        istringstream ss(in);
        double A; int B;
        ss >> A >> B;
        while(A < 1) A *= 10, B -= 1;
        // 在打好的表中寻找答案
        for(int i = 0; i <= 9; ++i) for(int j = 1; j <= 30; ++j) {
            if(B == E[i][j] && (fabs(A - M[i][j]) < 1e-4 || fabs(A / 10 - M[i][j]) < 1e-4)) {
                cout << i << ' ' << j << endl;
                break;
            }
        }
    }
}

12.7 high accuracy

https://www.cnblogs.com/ECJTUACM-873284962/p/6509429.html
uva 1828 fibonacci
https://www.xuebuyuan.com/1888279.html

#include <iostream>
#include <string.h>

using namespace std;

int f[5010][1010];       //第1个5010用来存5010个斐波那契数(测试可知第5000项已超过了1000位),第2个1010表示给每个斐波那契数开1010位

int main()
{
    int i, j;

    memset(f, 0, sizeof(f));

    f[1][0] = 1;        //给第1个斐波那契数置数
    f[2][0] = 1;        //给第2个斐波那契数置数

    for(i = 3; i < 5010; i++)      //从第3项开始,用前2项相加
    {
        int C = 0;      //C表示进位,开始设为0
        for(j = 0; j < 1001; j++)
        {
            f[i][j] = (f[i-2][j] + f[i-1][j] + C) % 10;     //%10后就是这一位该有的数字
            C = (f[i-2][j] + f[i-1][j] + C) / 10;       //相加产生的进位
        }

    }

    int a;
    while(cin>>a)
    {
        for(j = 1001; j >= 0; j--)      //寻找最高位
            if(f[a][j] != 0)
                break;
        for(; j >= 0; j--)
            cout<<f[a][j];
        cout<<endl;
    }
    return 0;
}

https://www.cnblogs.com/lqerio/p/11117608.html

12.9 c++ stl

https://www.cnblogs.com/lqerio/p/13484897.html
https://www.cnblogs.com/lqerio/p/11117601.html

12.10 滑动窗口 Sliding window

https://www.cnblogs.com/lqerio/p/11708680.html
https://www.cnblogs.com/lqerio/p/9741044.html

12.11 双指针...三指针... two-pointer

https://www.cnblogs.com/lqerio/p/11755868.html

原文地址:https://www.cnblogs.com/lqerio/p/13535931.html