Skip to content

Latest commit

 

History

History
1767 lines (1639 loc) · 38.7 KB

Initial_temple.md

File metadata and controls

1767 lines (1639 loc) · 38.7 KB
背包问题:(找最大值)
V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}
eg:

#include<stdio.h>
int max_(int x,int y){
    if(x>y)
    return x;
    else
    return y;
}
int main(){
    int t;
    while(~scanf("%d",&t)){
        while(t--){
            int m,u;
            int array_n[1024],array_v[1024],result[1024]={0};//n 价值 v 体积//result 当前背包容量下的已有的价值
            scanf("%d%d",&m,&u);
            for(int i=0;i<m;i++){
                scanf("%d",&array_n[i]);
            }for(int i=0;i<m;i++){
                scanf("%d",&array_v[i]);
            }
            for(int i=0;i<m;i++){//对前i个物品进行操作
                for(int j=u;j>=array_v[i];j--){
                    result[j]=max_(result[j],result[j-array_v[i]]+array_n[i]);
                }
            }int max=-1;

            for(int i=0;i<=u;i++){
                max=max_(max,result[i]);
            }
            printf("%d\n",max);
        }
    }return 0;
}

背包问题:(找最小值)
#include<stdio.h>
#include<string.h>
int dp[50024]={};
int min(int x,int y){
    if(x>y)
        return y;
    else
        return x;
}
int main(){
    int t;
    while(~scanf("%d",&t)){
        while(t--){
            int e,f;
            scanf("%d%d",&e,&f);
            int n;
            scanf("%d",&n);
            int m[100024];
            int v[100024];
            memset(dp,50001,50024*sizeof(int));
            dp[0]=0;
            for(int i=0;i<n;i++){
                scanf("%d%d",&m[i],&v[i]);
            }
            for(int i=0;i<n;i++){
                for(int j=v[i];j<=f-e;j++){
                    dp[j]=min(dp[j],dp[j-v[i]]+m[i]);
                }
            }
            if(dp[f-e]!=dp[50023])
                printf("The minimum amount of money in the piggy-bank is %d.\n",dp[f-e]);
            else
                printf("This is impossible.\n");
        }
    }return 0;
}

错排:
d(n)=(n-1)*(d(n-1)+d(n-2))

匈牙利算法:
eg:

#include<cstdio>
#include<cstring>
using namespace std;
//有n只公牛和m只母牛,然后每只公牛都可以和几只的母牛配对。
//在每只公牛只能配对一只母牛的情况下,求能为牛们配对最多多少对?
int n,m,ans;
int match[210];//母牛i的配偶是公牛match[i]
bool chw[210];//在此趟询问中,母牛i是否被询问过
bool mp[210][210];//公牛i与母牛j是否有关系  
 
bool find_ans(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(mp[x][i]==true&&chw[i]==true)
		{
			chw[i]=false;
			if(match[i]==0||find_ans(match[i])==true)
			//母牛没有配偶||匹配该母牛的公牛能否换一头母牛匹配 
			{
				match[i]=x;
				return true;
			}
		}
	}
	return false;
}
 
int main()
{
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		memset(mp,false,sizeof(mp));
		for(int i=1;i<=n;i++)
		{
			int k,x;
			scanf("%d",&k);
			for(int j=1;j<=k;j++)
			{
				scanf("%d",&x);
				mp[i][x]=true;
			}
		}
		ans=0;
		memset(match,0,sizeof(match));
		for(int i=1;i<=n;i++)
		{
			memset(chw,true,sizeof(chw));
			if(find_ans(i)==true) 
                ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

选数问题(和为素数):
#include <stdio.h>

int sushu(int n);
void fun(int n, int m);

int a[22], b[21], n, k, t = 0;

int main()
{
    int i;
    scanf("%d%d", &n, &k);
    int b[k];
    for(i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    fun(n, k);
    printf("%d", t);
}

void fun(int n, int m)//从n里面选m个数字 
{
    int i, sum;
    if(m == 0)
    {
        sum = 0;
        for(i = 0; i < k; i++)
            sum += b[i];
        if(sushu(sum))
            t++;
        return;
    }
    for(i = n ; i >= m; i--)
    {
        b[m - 1] = a[i];
        fun(i - 1, m - 1); 
    }
}

int sushu(int n)
{
    int i;
    for(i = 2; i < n; i++)
        if(n % i == 0)
            break;
    if(i == n || n == 2)
        return 1;
    else
        return 0;
}

装箱问题:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
 
int n;
int d[20005];
int a[35];
int main(){
	int w;
	scanf("%d%d", &w, &n);
	int i, j;
	for (i = 0; i < n; i++){
		scanf("%d", &a[i]);
	}
	memset(d, 0, sizeof(d));
	for (i = 0; i < n; i++){
		for (j = w; j >= a[i]; j--)
			d[j] = max(d[j], d[j - a[i]] + a[i]);
			
	}
	printf("%d\n", w - d[w]);
	return 0;
}

dp思想:
#include<stdio.h>
int max_(int x,int y){
    if(x<y)
        return y;
    else
        return x;
}
int main(){
    int x;
    while(~scanf("%d",&x)){
        if(x==0)
            return 0;
        int array[1024];
        int group[1024];
        int count=0;
        while(x--){
            scanf("%d",&array[count++]);
            group[count-1]=array[count-1];
        }
        for(int i=0;i<count;i++){
            for(int j=0;j<i;j++){
                if(array[j]<array[i])
                    group[i]=max_(group[i],group[j]+array[i]);
            }

        }
        int sum=0;
        for(int i=0;i<count;i++){
            sum=max_(sum,group[i]);
        }
        printf("%d\n",sum);
    }return 0;
}

最长公共子序列(LCS)问题:
公式:
a[i-1]==b[i-1]-->dp[i-1][j-1]+1
a[i]!=b[i]-->max{dp[i-1][j],dp[i][j-1]}
eg:
#include<stdio.h>
#include<string.h>
int max(int x,int y){
    if(x<y)
        return y;
    else
        return x;
}
int dp[1024][1024];
int main(){
    char a[1024],b[1024];
    while(~scanf("%s%s",a,b)){
        int len=max(strlen(a),strlen(b));
        for(int i=0;i<=len;i++){
            for(int j=0;j<=len;j++){
                dp[i][j]=0;
            }
        }
        for(int i=1;i<=strlen(a);i++){
            for(int j=1;j<=strlen(b);j++){
                if(a[i-1]==b[j-1]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
                }
            }
        }
        printf("%d\n",dp[strlen(a)][strlen(b)]);
    }return 0;
}

LCS一维数组(慢):
#include<cstdio>
#include<iostream>
int x,maxl,ans,f[100005];
int arr1[100005],arr2[100005];
using namespace std;
int main(){
    scanf("%d",&x);
    for(int i=0;i<x;i++){
        scanf("%d",&arr1[i]);
    }   
    for(int i=0;i<x;i++){
        scanf("%d",&arr2[i]);
    }
    for(int i=0;i<x;i++){
        maxl=0;
        for(int j=0;j<x;j++){
            int ll=f[j];
            if(arr1[i]==arr2[j]&&f[j]<maxl+1)
                f[j]=maxl+1;
            maxl=max(maxl,ll);
        }
    }
    for(int i=0;i<x;i++){
        if(ans<f[i]){
            ans=f[i];
        }
    }
    printf("%d\n",ans);
    return 0;
}

埃式塞:(快速求质数)
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int main()
{
  // 埃氏筛

  // 0 表示质数,1 非质数(1 非质非合)
  int arr[101] = { 0 };  // 0 去掉,1~100
  arr[1] = 1;  // 1 既不是质数也不是合数

  for (int i = 2; i <= 100; ++i) {
    if (arr[i] == 1)
      continue;
    for (int i_times = i * 2; i_times <= 100; i_times += i) {
      arr[i_times] = 1;   // i 的 n 倍必然是合数
    }    
  }

  int cnt = 0;
  for (int i = 1; i <= 100; ++i) {
    cnt += (arr[i] + 1) % 2;
  }
  cout << cnt << endl;
  return 0;
}

线性筛素数:
#include<bits/stdc++.h>
using namespace std;
int n;
map<int,int> Is_Prime;//保存每一个数是否为质数
vector<int> Prime;//保存全部质数
int main()
{
	scanf("%d",&n);//筛选2~n内的质数
	for(int i=2;i<=n;i++) Is_Prime[i]=1;//先默认全部都是质数
	for(int i=2;i<=n;i++)
	{
		if(Is_Prime[i]) Prime.push_back(i);//如果这个数是质数,就将其保存下来
		for(int j=0;j<Prime.size();j++)//将这个数与已有的质数进行操作
		{
			Is_Prime[i*Prime[j]]=0;//将这个数与该质数的积标记为非质数
			if(!(i%Prime[j])) break;//如果当前数是该质数的倍数,就退出循环
		}
	}
    //以下为输出部分
	printf("%d\n",Prime.size());
	for(int i=0;i<Prime.size();i++) printf("%d ",Prime[i]);
	return 0;
}

欧拉筛(上述筛,数组形式/速度更快):
#include<cstdio>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
int n,q;
int ls[100000005];
int prime[100000005];
int main(){
    scanf("%d%d",&n,&q);
    int count=0;
    for(int i=2;i<=n;i++){
        ls[i]=1;
    }for(int i=2;i<=n;i++){
        if(ls[i])
            prime[count++]=i;
        for(int j=0;j<count&&prime[j]*i<=n;j++){
            ls[i*prime[j]]=0;
            if(!(i%prime[j]))
                break;
        }
    }
    while(q--){
        int x;
        scanf("%d",&x);
        printf("%d\n",prime[x-1]);
    }
}

sort排序:
#include<iostream>
#include<algorithm>
using namespace std;
int array[1024];
int main(){
    int count=0;
    while(cin>>array[count]){
        count++;
        if(getchar()=='\n'){
            break;
        }
    }
    sort(array,array+count);
    for(int i=0;i<count;i++){
        cout<<array[i]<<endl;
    }
    return 0;
}

选择排序法:
#include<stdio.h>
int main() 
{
	int array[5],n=5;
	for(int i=0;i<n;i++){
		scanf("%d",&array[i]);
	}
	    int i,j,k,t;
	    for(i=0;i<n-1;i++){
		    k=i;
		    for(j=i+1;j<n;j++){
			    if(array[j]<array[k]){
			    	 k=j;
			       	 t=array[k];
		    		 array[k]=array[i];
	     			 array[i]=t;
			    }
		    }  
	    }
	for(int i=0;i<n;i++){
		printf("%d",array[i]);
	}
	
	return 0;
}


快速求因子的函数:
(个数)
long long f(long long a){
    long long sum = 0;
    for(long long i = 1;i <= a/i;i++){
        if(a % i == 0)
            if(i * i != a)
                sum += 2;
            else
                sum++;
    }
    return sum;
}
(数据+个数)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int array[1024];
int f(int x){
    int now=0;
    for(int i=1;i*i<=x;i++){
        if(x%i==0){
            array[now++]=i;
            if(i!=x/i){
                array[now++]=x/i;
            }
        }
    }
    sort(array,array+now);
    return now;
}
int main(){
    int x;
    scanf("%d",&x);
    int sum=f(x);
    for(int i=0;i<sum;i++){
        printf("%d ",array[i]);
    }return 0;
}


二分查找(仅递增):
#include<stdio.h>
//二分查找-C语言实现
//基本思路:将排序好的数据存放到数组里(不能是链表)
//        这只前中后标签,与中间元素比,若小于就将后变为原来的中
//        继续计算中,比较,循环,直至等于中,或循环结束。
int binsearch(int *sortedSeq, int seqLength, int keyData);
int main(){
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int location;
    int target = 4;
    location = binsearch(array, 9, target);
    printf("%d\n", location);
    return 0;
}
int binsearch(int *sortedSeq, int seqLength, int keyData){
    int low = 0, mid, high = seqLength - 1;

    while (low <= high){
        mid = (low + high) / 2;//奇数,无论奇偶,有个值就行
        if (keyData < sortedSeq[mid]){
            high = mid - 1;//是mid-1,因为mid已经比较过了
        }
        else if (keyData > sortedSeq[mid]){
            low = mid + 1;
        }
        else{
            return mid;
        }
    }
    return -1;
}

二分查找(不递减):
#include<stdio.h>
int array[1000005];
int group[1000005];
int main(){
    int m,n;
    scanf("%d %d",&m,&n);
    for(int i=0;i<m;i++){
        scanf("%d",&array[i]);
    }
    for(int i=0;i<n;i++){
        int x;
        scanf("%d",&x);
        int low=0,mid,high=m-1;
        while(low<high){
            mid=(low+high)/2;
            if(x<array[mid]){
                high=mid-1;
            }
            else if(x>array[mid]){
                low=mid+1;
            }
            else{
                high=mid;
            }
        }
        if(array[high]==x){
            group[i]=high+1;
        }
        else
            group[i]=-1;
    }
    for(int i=0;i<n;i++){
        printf("%d ",group[i]);
    }
    return 0;
}

十进制转换为二进制代码:
#include <iostream>
using namespace std;
int main()
{
    int num;
    int length = 0;
    int n[20];
    cout << "十进制:";
    cin >> num;
    //循环除2,把余数存储在数组中
    while (num / 2)
    {
        n[length] = num % 2;
        length++;
        num = num / 2;
    }
    //存储最后一个余数
    n[length] = num;
    length++;
    cout << "二进制:";
    //将余数从下往上输出
    for (int i = length - 1; i >= 0; i--)
    {
        cout << n[i];
    }
    return 0;
}

(简易,不能重叠)朋友圈问题(给定人数,已知几对关系,求朋友圈的问题):
#include <stdio.h>
#include <stdlib.h>
int root[100010];
int search(int men)
{
    int now;
    now=men;
    while(root[men]!=men)
    {
        men=root[men];
    }
    if(now!=men)
    {
        root[now]=root[men];
    }
    return men;
}
int main()
{
    int n,m,num,i;
    scanf("%d%d",&n,&m);
    num=0;
    for(i=1;i<=n;i++)
        root[i]=i;
    while(m--)
    {
        int men1,men2,root1,root2;
        scanf("%d%d",&men1,&men2);
        root1=search(men1);
        root2=search(men2);
        if(root1!=root2)
        {
            root[men1]=men2;                                                                             
        }
    }
    for(i=1;i<=n;i++){
        if(root[i]==i)
        num++;
	}
    printf("%d",num);
    return 0;
}

二分法统计数组值(有序):
#include <stdio.h>
int GetFirstKey(int arr[], int left, int right, int len, int key)
{
	int mid;
	if (left > right)
	{
		return -1;
	}
	mid = left - (left - right) / 2;
	if (key == arr[mid])
	{
		if ((mid > 0 && arr[mid - 1] != key) || mid == 0)
		{
			return mid;
		}
		else
		{
			right = mid - 1;
		}
	}
	else if (arr[mid] < key)
	{
		left = mid + 1;
	}
	else
	{
		right = mid - 1;
	}
	return GetFirstKey(arr, left, right, len, key);
}
 
int GetLastKey(int arr[], int left, int right, int len, int key)
{
	int mid;
	if (left > right)
	{
		return -1;
	}
	mid = left - (left - right) / 2;
	if (key == arr[mid])
	{
		if ((mid < len - 1 && arr[mid + 1] != key || mid == len - 1))
		{
			return mid;
		}
		else
		{
			left = mid + 1;
		}
	}
	else if (arr[mid] < key)
	{
		left = mid + 1;
	}
	else
	{
		right = mid - 1;
	}
	return GetLastKey(arr, left, right, len, key);
}
 
int  main()
{
	int brr[] = { 1, 2, 3, 3, 3, 3, 4, 5};
	int len = sizeof(brr) / sizeof(brr[0]);
	int first = GetFirstKey(brr, 0, len - 1, len - 1, 3);
	int last = GetLastKey(brr, 0, len - 1, len - 1, 3);
	printf("%d\n", last - first + 1);
	return 0;
}

并查集问题(朋友的朋友是朋友形式):
#include<bits/stdc++.h>
using namespace std;
#define MAX 1010
 
int qw[MAX];
int maxn;
 
void init() {//遍历所有同学,使他们拥有初始值。
    for (int i = 0; i < MAX; i++) {
        qw[i] = i;
    }
}
 
void update(int minab, int maxab) {//如果最小的那个值为-1 说明这个人使qw的粉丝
    for (int i = 0; i < MAX; i++) {
        if (qw[i] == maxab) {
            qw[i] = minab;// -1 一定小于所有遍历过的值,使那个maxab学生的值也为-1
        }
    }
}
 
void print() {//用于调试的函数
    for (int i = 0; i <= maxn; i++) {
        cout << qw[i] << ' ';
    }
    cout << endl;
}
 
int count() {//遍历所有学生统计qw的粉丝。
    int ans = 0;
    for (int i = 0; i < MAX; i++) {
        if (qw[i] == -1) {
            ans++;
        }
    }
    return ans;
}
 
int main() {
    int n, m, fans;
    while (cin >> n >> m) {
        maxn = 0;
        if (n == 0 && m == 0) {
            break;
        }
        init();
        for (int i = 0; i < n; i++) {
            cin >> fans;
            maxn = max(maxn, fans);
            qw[fans] = -1;
        }
        int a, b;
        for (int i = 0; i < m; i++) {
            cin >> a >> b;
            maxn = max(maxn, max(a, b));
            update(min(qw[a], qw[b]), max(qw[a], qw[b]));
            // print();
        }
    //print();
        cout << count() << endl;
    }
    return 0;
}

并查集改良版:
#include<bits/stdc++.h>
using namespace std;
#define MAX 6000
 
int qw[MAX];
int maxn;
int n, m, p;
 
void init() {//遍历所有同学,使他们拥有初始值。
    for (int i = 0; i < MAX; i++) {
        qw[i] = i;
    }
}
 
void update(int minab, int maxab) {//使下标最小的数值为根,和根有关系的变成根的数值
    for (int i = 0; i < MAX; i++) {
        if (qw[i] == maxab) {
            qw[i] = minab;
        }
    }
}
 
void print() {//用于调试的函数
    for (int i = 0; i <= maxn; i++) {
        cout << qw[i] << ' ';
    }
    cout << endl;
}
 
int count() {//遍历所有学生统计qw的粉丝。
    int ans = 0;
    for (int i = 0; i < MAX; i++) {
        if (qw[i] == -1) {
            ans++;
        }
    }
    return ans;
}
 
int main() {
    cin >> n >> m>> p;
        maxn = 0;
        init();
        int a, b;
        for (int i = 0; i < m; i++) {
            cin >> a >> b;
            maxn = max(maxn, max(a, b));
            update(min(qw[a], qw[b]), max(qw[a], qw[b]));
            // print();
        }
        print();
    while(p--){
        int x,y;
        cin>>x>>y;
        if(qw[x]==qw[y]){
            printf("Yes\n");
        }
        else{
            printf("No\n");
        }
    }
    return 0;
}

寻找最长回文子串:
动态规划找:
当 i == j,dp[i][j]是回文子串(单字符都是回文子串);
当j - i < 3,只要s[i] == s[j],则dp[i][j]是回文子串(如 aa,aba),否则不是;
当j - i >= 3,如果s[i] == s[j] && dp[i+1][j-1],则dp[i][j]是回文子串,否则不是。
中间扩散找:
#include <stdio.h>
#include <string.h>
int main()
{
    char w[1210];
    int i,len,max,j,k,x,y;
    while(~scanf("%s",w))
    {
        int a[1210]={1},b[1210]={0};//a全部为一 表示回文串至少为1 b全部置0
        len=strlen(w);//得到字符串长度
        for(i=0;i<len;i++)//找奇数回文子串
        {
            j=i-1;//子串是回文的话至少长度为三
            k=i+1;
            while(j>=0 && k<len && w[j]==w[k])//先找到最小的是回文的串 再判断更多的
            {
                    x=j;
                    y=k;
                    a[i]=k-j+1;
                j--;//找有五位时是否还为回文字符串
                k++;
            }
        }
        for(i=0;i<len;i++)//偶数回文找法
        {
            j=i;
            k=i+1;
            while(j>=0 && k<len && w[j]==w[k])
            {
                    b[i]=k-j+1;
                j--;//先看中间是不是回文 再看两边
                k++;
            }
        }
        max=1;
        for(i=0;i<len;i++)
        {
            if(max<a[i])
                max=a[i];
            if(max<b[i])
                max=b[i];
        }
        printf("%d\n",max);
    }
    return 0;
}

全排类问题:
#include <iostream>
#include <algorithm>
using namespace std;

int arr[100010];

void printArr(int* arr, int size) {
    for (int i = 0; i < size; ++i) {
        if (i != 0) cout << ' ';
        cout << arr[i];
    }
    cout << endl;
}

int main()
{
    // sample input:
    // 4
    // 1 2 1 2

    // sample output:
    // 1 1 2 2
    // 1 2 1 2
    // 1 2 2 1
    // 2 1 1 2
    // 2 1 2 1
    // 2 2 1 1
    // P(4, 4) / (P(2, 2) * P(2, 2))

    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }


    sort(arr, arr + n);
    printArr(arr, n);

    // arr “改变了” 返回 true,否则返回 false
    while (next_permutation(arr, arr + n))
        printArr(arr, n);

    return 0;
}

迷宫问题:
#include<stdio.h>
int book[51][51],a[51][51];//book[][]等于0表示该点还没有走过 a[][]等于0表示该点不是障碍
int n,m,p,q,min=99999;
	int next[4][2]={
 		    {0,1}, //向右走一步
					{1,0},//向下走一步
					{0,-1},//向左走一步
					{-1,0}};//向上走一步

void dfs(int x,int y,int step){   //step用来表示找到小红,小明走了多少步
	int tx,ty,k;
	if(x==p&& y==q){  //说明已经找到了小红  
	/*
	还要说明一点:这里 为什么是(x,y),而不是(tx,xy) 
	其实很简单 就是上一个dfs()函数传过来的坐标 ,做了这个dfs()函数的形参 
	换句话说:就是判断点是否找到小红 
	*/ 

		if(step<min)
			min=step;
		return ;   
		/*返回上一步,继续寻找其他路径(就是退回到上一个坐标,重新找其他路径)
		   回到上一个dfs()函数 
		
		*/ 
		}
		
	for(k=0;k<=3;k++){   //下一步的坐标
		tx=x+next[k][0]; 
		ty=y+next[k][1];
	
			//判断是否越界,越界则重新进入for循环 
			if(tx<1 || tx>n || ty<1 || ty>m)
				continue;  
				//运行到这里,说明这条路,则需要换个方向,也就是重新进入for循环
			if(a[tx][ty]==0 && book[tx][ty]==0){
				book[tx][ty]=1; //标记这个点走过
				dfs(tx,ty,step+1); //进行下一步
				book[tx][ty]=0;   //重新尝试,退回到上一个点的位置
		}
	
		}
		return ;   //执行到这里,这层dfs()函数已经结束,则要回到上一层dfs()函数 
}

int main(){
	int i,j,startx,starty;
	scanf("%d %d",&n,&m);    //输入迷宫的大小 
	
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			scanf("%d",&a[i][j]);  //输入迷宫的形状 
	
	scanf("%d %d",&startx,&starty);  //小明的坐标 
	scanf("%d %d",&p,&q);            //小红的坐标 
	
	book[startx][starty]=1;         //起始点标记,就不会回到这个点了 
	dfs(startx,starty,0);      //开始寻找最短路径 
	
	printf("%d",min);        //输出最短路径 
	return 0;
}

三角形路径求最大值(dp):
#include<cstdio>
#include<iostream>
using namespace std;
int n,a[1002],i,j,ans,p;
int main(){
    scanf("%d",&n);
        for(i=n;i;i--){
            for(j=i;j<=n;j++){
               scanf("%d",&p);
                    a[j]=max(a[j],a[j+1])+p;
            }
        }
    for(i=1;i<=n;i++)
        ans=max(ans,a[i]);
    printf("%d",ans);
    return 0;
}

BFS(障碍为1,通路为0)://(有些需要用数组标记)
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
int Map[5][5];  //定义地图大小
int dir[4][2]= {{1,0},{-1,0},{0,-1},{0,1}};  //定义方向
int n,m,ans;
struct node
{
    int x,y,step;

} now,nextt;  //保存走步
int BFS(int x,int y)
{
    queue<node> q;
    int xx,yy,zz;
    Map[x][y]=2;  //走过初始点
    now.x=x;
    now.y=y;
    now.step=0;
    q.push(now);  //从当前点开始
    while(!q.empty())  //ture 非false的条件是非空
    {
        now=q.front();
        q.pop();
        for(int i=0; i<4; i++)  //遍历四个方向
        {
            xx=now.x+dir[i][0];
            yy=now.y+dir[i][1];  //走一步
            if(xx>=0&&xx<5&&yy>=0&&yy<5&&Map[xx][yy]!=1&&Map[xx][yy]!=2)  //可以走
            {
                nextt.x=xx;
                nextt.y=yy;
                nextt.step=now.step+1;  //步数加一
                Map[now.x][now.y]=2;   //走过一个点
                if(Map[xx][yy]==3)  //到达终点
                    return nextt.step;
                q.push(nextt);

            }
            // for(int i=0; i<5; i++){      //打印地图
            //     for(int j=0; j<5; j++)
            //         cout << Map[i][j];
            //     cout << endl;
            // }
            // cout << endl;
        }
    }
    return -1;   //走不过去
}

int main()
{

    for(int i=0; i<5; i++)     //输入地图
        for(int j=0; j<5; j++)
            cin >> Map[i][j];
    Map[4][4]=3;  //定义终点
    ans=BFS(0,0);
    cout << ans<< endl;
    return 0;

}

岛屿问题:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
 
int n;
char mapp[MAXN][MAXN];
int vis[MAXN][MAXN];
int wsad[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
 
struct node {
    int x, y;
};
 
void bfs(node x) {
    queue<node> q;
    q.push(x);
    node t, nx;
    vis[x.x][x.y] = 1;
    mapp[x.x][x.y] = 'o';
    while (!q.empty()) {
        t = q.front();
        q.pop();
        for (int i = 0; i < 4; i++) {
            nx.x = t.x + wsad[i][0];
            nx.y = t.y + wsad[i][1];
 
            if ((nx.x >= 0 && nx.x < n) && (nx.y >= 0 && nx.y < n) && \
                vis[nx.x][nx.y] == 0 && mapp[nx.x][nx.y] != 'o') {
                vis[nx.x][nx.y] = 1;
                mapp[nx.x][nx.y] = 'o';
                q.push(nx);
            }
        }
    }
}
 
void Print() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cout << mapp[i][j] << ' ';
        }
        cout << endl;
    }
    cout << endl;
}
 
int main() {
    while(cin >> n) {
        int ans = 0;
        memset(vis, 0, sizeof(vis));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> mapp[i][j];
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (mapp[i][j] == 'x') {
                    node x;
                    x.x = i; 
                    x.y = j;
                    bfs(x);
                    // Print();
                    ans++;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

删数问题取最小值(去除前导零):
#include<cstdio>
#include<cstring>
#include<iostream>
int main(){
    char array[300];
    scanf("%s",array);
    int x;
    scanf("%d",&x);
    int len=strlen(array);
    while(x){
        int i=0;
        while(array[i]<=array[i+1]){
            i++;
        }
        while(i<len-1){
            array[i]=array[i+1];
            i++;
        }
        len--;
        x--;
    }
    int flag=1;
    for(int i=0;i<len;i++)         
    {
        if(array[i]=='0'&&i<len-1&&flag==1)  
            continue;           
        else{
            printf("%c",array[i]);
            flag=0;
        }
    }return 0;
}

求第 k 小的数(nth_element):
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int array[5000005];
int main(){
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&array[i]);
    }
    nth_element(array,array+k,array+n);
    printf("%d",array[k]);
    return 0;
}

拼数(string类型的使用):
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
string array[25];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        cin>>array[i];
    }
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            if(array[i]+array[j]<array[j]+array[i]){
                swap(array[i],array[j]);
            }
        }
    }
    for(int i=0;i<n;i++)
    {
        cout<<array[i];
    }
    return 0;
}

最大子串和:
#include<cstdio>
#include<iostream>
using namespace std;
int array[200005];
int main(){
    int n;
    scanf("%d",&n);
    int max=-99999;
    int sum=0;
    for(int i=0;i<n;i++){     
        scanf("%d",&array[i]);
        sum+=array[i];
        if(sum>max){
            max=sum;
        }
        if(sum<0){
            sum=0;
        }
    }
    printf("%d",max);
    return 0;
}

求最大矩形和(二维):
#include<stdio>
#include<iostream>
using namespace std;
int ans,a[155][155],n;
int maxn(int a,int b){return a>b?a:b;}
//自定义求最大值
int main(){
	scanf("%d",&n);
	int i,j,k;
	for(i=1;i<=n;++i){
		for(j=1;j<=n;++j){
			scanf("%d",&a[i][j]);
			a[i][j]+=a[i-1][j];
		}
	}//如上,前缀和处理
	for(i=1;i<=n;++i){
		for(k=1;k<=i;++k){
			int f[150]={0},dp[150]={0};//f[j]表示压缩的矩形第j列的值
			for(j=1;j<=n;++j){			//其实可以不开数组,一个f就可以
				f[j]=a[i][j]-a[i-k][j];//求压缩的矩形第j列的值
				dp[j]=maxn(dp[j-1]+f[j],f[j]);//动态规划
				ans=maxn(ans,dp[j]);//更新答案
			}
		}
	}
	cout<<ans<<endl;//愉快AC
	return 0;
}

st表模板:
//预处理复杂度同为O(nlogn),查询时间上,ST表为O(1),线段树为O(logn)
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int a[N];//原始输入数组
//st表,表示需要查询的数组的从下标i到下标i+2^j-1的最值
int mx[N][30];//最大值 
int mn[N][30];//最小值 
 
//预处理 
void init(int n)
{
    for(int i=1;i<=n;i++){
    	mx[i][0]=a[i];
    	mn[i][0]=a[i];
	}
 
    for(int j=1;(1<<j)<=n;j++)
    {
        for(int i=1;i+(1<<j)<=n+1;i++){
        	mn[i][j] = min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
        	mx[i][j] = max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
		}
    }
}
 
//查询函数 
int search(int l,int r)//l和r范围为1~n 
{
	int k=log2(r-l+1);
	int t1=min(mn[l][k],mn[r-(1<<k)+1][k]);//区间最小值 
	int t2=max(mx[l][k],mx[r-(1<<k)+1][k]);//区间最大值 
	return t2-t1;
}
 
int main(){
//	freopen("in.txt","r",stdin);
	int n,q;scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) 
        scanf("%d",&a[i]);
	init(n);
	while(q--){
		int l,r;
        scanf("%d%d",&l,&r);
		printf("%d\n",search(l,r));
	}
	return 0;
}
 
lower_bound()与upper_bound()的用法:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
	vector<int> ve(8, 0);
	for (int i = 0; i < 8; i++)
	{
		ve[i] = i;
	}
	auto low = lower_bound(ve.begin(), ve.end(), 3)-ve.begin();
	int upp = upper_bound(ve.begin(), ve.end(), 3) - ve.begin();
	cout<<low<<endl;
	cout << upp << endl;
}

3
4


kmp板子:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
const int maxn=1000005;
using namespace std;
string s,p;
int nxtpos[maxn],lcpp[maxn],nxtpos0[maxn];//nxtpos0为未优化版nxtpos数组
void getnxt()
{
    nxtpos[0]=-1;
    nxtpos0[0]=-1;
    int len = p.length();
    int j=0,k=-1;
    while(j <= len - 1)
    {
        if(k==-1||p[j]==p[k])
        {
            j++;
            k++;
            nxtpos0[j]=k;
            if(p[j]!=p[k])
            {
                nxtpos[j] = k;
            }
            else
            {
                nxtpos[j] = nxtpos[k];
            }
        }
        else
        {
            k = nxtpos0[k];
        }
    }
}
void kmp()
{
    int i=0,j=0;
    int slen=s.length();
    int plen=p.length();
    while(i < slen)
    {
        if(j == -1||p[j] == s[i])
        {
            i++;
            j++;
        }
        else
        {
            j=nxtpos0[j];
        }
        if(j==plen)
        {
            printf("%d\n",i-j+1);
            i=i-j+1;
            j=0;
        }
    }
}
int main()
{
    cin>>s>>p;
    getnxt();
    kmp();
    for(int i=0;i<p.length();i++)
    {
        lcpp[i]=nxtpos0[i+1];
        printf("%d ",lcpp[i]);
    }
    return 0;
}

AC自动机模板:

#include <queue>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn =  2*1e6+9;

int trie[maxn][26]; //字典树
int cntword[maxn];  //记录该单词出现次数
int fail[maxn];     //失败时的回溯指针
int cnt = 0;

void insertWords(string s){
    int root = 0;
    for(int i=0;i<s.size();i++){
        int next = s[i] - 'a';
        if(!trie[root][next])
            trie[root][next] = ++cnt;
        root = trie[root][next];
    }
    cntword[root]++;      //当前节点单词数+1
}
void getFail(){
    queue <int>q;
    for(int i=0;i<26;i++){      //将第二层所有出现了的字母扔进队列
        if(trie[0][i]){
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }

//fail[now]    ->当前节点now的失败指针指向的地方
//tire[now][i] -> 下一个字母为i+'a'的节点的下标为tire[now][i]
    while(!q.empty()){
        int now = q.front();
        q.pop();

        for(int i=0;i<26;i++){      //查询26个字母
            if(trie[now][i]){
                //如果有这个子节点为字母i+'a',则
//让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
                //有点绕,为了方便理解特意加了括号

                fail[trie[now][i]] = trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else//否则就让当前节点的这个子节点
                //指向当前节点fail指针的这个子节点
                trie[now][i] = trie[fail[now]][i];
        }
    }
}


int query(string s){
    int now = 0,ans = 0;
    for(int i=0;i<s.size();i++){    //遍历文本串
        now = trie[now][s[i]-'a'];  //从s[i]点开始寻找
        for(int j=now;j && cntword[j]!=-1;j=fail[j]){
            //一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).
            ans += cntword[j];
            cntword[j] = -1;    //将遍历国后的节点标记,防止重复计算
        }
    }
    return ans;
}

int main() {
    int n;
    string s;
    cin >> n;
    for(int i=0;i<n;i++){
        cin >> s ;
        insertWords(s);
    }
    fail[0] = 0;
    getFail();
    cin >> s ;
    cout << query(s) << endl;
    return 0;
}

数列分段(要求分段结果的最大值最小):
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,x[100005],sum=0,max1=0;
int judge(int sum1)
{
    int num=1;
    int temp=0;
    for(int i=0;i<n;i++) //分段
    {
        temp+=x[i];
        if(temp>sum1)
        {
            num++;
            temp=x[i];
        }
    }
    if(num>m) //分出的段数大于该有的段数
        return 1;
    return 0;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)  
    {
        cin>>x[i];
        sum+=x[i];
        if(x[i]>max1)
            max1=x[i];
    }
    int l=max1,r=sum;  //查阅的满足条件的数介于数列的最大值和数列的中间值
    while(l<r)
    {
        int mid=(l+r)/2;
        if(judge(mid))
            l=mid+1;
        else 
            r=mid;
    }
    cout<<r<<endl;
    return 0;
}

在一定区域内改变数值(dfs):
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int a[31][31],vis[31][31],n;
void dfs(int x,int y){
    if(x<0||x>n-1||y<0||y>n-1||a[x][y]==1||vis[x][y]==1) return;//出界或撞墙
    vis[x][y]=1;//标记
    dfs(x,y+1);//上下左右
    dfs(x,y-1);
    dfs(x+1,y); 
    dfs(x-1,y);
}
int main(){
    int i,j;
    memset(vis,0,sizeof(vis));
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    for(i=0;i<n;i++) dfs(0,i);//四面开始遍历
    for(i=0;i<n;i++) dfs(i,0);
    for(i=n-1;i>=0;i--) dfs(i,n-1);
    for(i=n-1;i>=0;i--) dfs(n-1,i);
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
        {
            if(vis[i][j]==1) 
                printf("%d ",a[i][j]);//有标记,还输出0
            else if(vis[i][j]==0&&a[i][j]==1) 
                printf("%d ",a[i][j]);//墙当然不变了
            else
                printf("2 ");//剩下的就是圈内的了
        }//分两部分是因为每行最后数字的后面没有空格
        printf("\n");
    }
    return 0;
}

最大正方形:
#include<cstdio>
#include<iostream>
using namespace std;
int array[105][105];
int f[105][105];
int main(){
    int m,n;
    int ans=0;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&array[i][j]);
            if(array[i][j]==1){
                f[i][j]=min(min(f[i-1][j],f[i][j-1]),f[i-1][j-1])+1;
                ans=max(ans,f[i][j]);
            }
        }
    }
    printf("%d",ans);
    return 0;
}

#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
const int maxn=11000000+5;
string ma="@#";
int mp[2*maxn]; //存放回文串长度+1
void manacher(string s){
	int len=s.size();
	for (int i=0; i<len; i++){
		ma+=s[i];
		ma+='#';
	}
	int nlen=ma.size();
	int mx=0,id=0;	//mx为最右端位置,id为能延伸到最右边的字符串的中心位置
	for (int i=0; i<nlen; i++){
		mp[i]=(i>mx)?1:min(mp[2*id-i],mx-i); //每次取小赋值,防止超过mx
		while (ma[i+mp[i]]==ma[i-mp[i]]) mp[i]++; 
		if (i+mp[i]>mx){
			mx=i+mp[i];
			id=i;
		}
	}
}


int main(){
	
	ios::sync_with_stdio(false);
	string s;
	cin>>s;
	int len=s.size();
	manacher(s);
	int ans=0;
	for (int i=0; i<2*len+2; i++)
		ans=max(ans,mp[i]-1);
	cout<<ans;
	return 0;
} 

逆元:(结果为1-n)
扩展欧几里得算法
扩展欧几里得算法是求整数x、y 使得 ax+by=1
单点查找素数快,在a与p互质而p不是质数也可以使用
#include <iostream>
using namespace std;
typedef long long ll;
void Exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)	x=1,y=0;
	else
	{
		Exgcd(b, a%b, y, x);
		y-=a/b*x;
	}
}
int main()
{
	ll x,y,n,p;
	cin>>n>>p;
	for(int i=1;i<=n;i++)
	{
		Exgcd(i,p,x,y);
		x=(x%p+p)%p;
		cout<<x<<endl;
	}
	return 0;
}

快速幂(费马小定理)
费马小定理 :若pp为素数,aa为正整数,且aa、pp互质。 则有a(p-1) ≡1(modp)。
代入式子化简得 x≡ap−2(modp)
#include <iostream>
using namespace std;
typedef long long ll;
ll fpm(ll x,ll power, ll p)
{
	x%=p;
	ll ans=1;
	for(;power;power>>=1)
	{
		if(power&1)
		{
			ans*=x;
			ans%=p;
		}
		x*=x;
		x%=p;
	}
	return ans;
}
int main()
{
	ll n,p;
	cin>>n>>p;
	for(int i=1;i<=n;i++)
	{
		ll x = fpm(i, p-2, p); //x为a在mod p意义下的逆元
		cout<<x<<endl;
	}
	return 0;
 } 

线性算法
适用于求一连串的逆元
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e6+5;
ll inv[maxn];
int main()
{
	ll n,p;
	cin>>n>>p;
	inv[1]=1;
	cout<<inv[1]<<endl;
	for(int i=2;i<=n;i++)
	{
		inv[i]=(p - p / i) * inv[p % i] % p;
		printf("%lld\n",inv[i]);
	}
	return 0;
}