ACM模板(持续更新)

快读快输模板:

inline int read() {
	char ch = getchar();
	int x = 0, f = 1;
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}
inline void write(int x) {
	if (x < 0) x = ~x + 1, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');

}
输出后空格
void writespace(int x)
{
	write(x);putchar(32);return;//这里仍然利用了puchar速度快的优点
}
输出后换行
void writeln(int x)
{
	write(x);putchar(10);//依旧利用putchar快速的优点,达到十分快速的效果
}
inline void print(__int128 x) {
	if(x<0) {
		putchar('-');
		x=-x;
	}
	if(x>9)
		print(x/10);
	putchar(x%10+'0');
}

常用模板:

/*#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep1(i,a,b) for(int i=a;i<b;i++)
#define pre(i,a,b) for(int i=b;i>=a;i--)
#define pre1(i,a,b) for(int i=b;i>a;i--)
#define ll long long
#define eps 1e-10
#define mod 1e9+7
struct edge {
	int v,next;
} e[N<<1];
//typedef for(int i=1;i<=n;i++) rep(i,1,n);
//typedef for(int i=0;i<n;i++) rep(i,0,n);
//typedef for(int i=n;i>=1;i--) pre(i,1,n);
//typedef for(int i=n-1;i>=0;i--) pre(i,0,n);
double distance(double x1,double y1,double x2,double y2) {
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void add(int v,int u) {
	e[++cnt].next=head[v];
	e[cnt].v=u;
	head[v]=cnt;
}
void add1(int u,int v) {
	add(u,v);
	add(v,u);
}
void Prime(int n) {
	b[1]=1;
	for(int i=2; i<=n; i++) {
		if(!b[i])
			prime[++res]=i,id[i]=res;
		for(int j=1; j<=res&&i*prime[j]<=n; j++) {
			b[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
		}
	}
}
vector<int>v[700000 + 10];
void Init(int x,int c) {
	for(int i=1; prime[i]*prime[i]<=x; i++) {
		if(x%prime[i]==0) {
			while(x%prime[i]==0) x/=prime[i];
			v[i].push_back(c);
		}
	}
	if(x>1) v[id[x]].push_back(c);
}
int parent[N],cut[N];
void dfs(int x) {
	static int count=0;
	int child=0;
	low[x]=dfn[x]=++count;
	for(int i=head[x]; i; i=e[i].next) {
		int v=e[i].v;
		if(!dfn[v]) {
			parent[v]=x;
			child++;
			dfs(v);
			low[x]=min(low[x],low[v]);
			if(!cut[x]&&(!parent[x]&&child>=2||parent[x]&&low[v]>=dfn[x])) {
				ans++;
				cut[x]=1;
			}
		} else if(parent[x]!=v)
			low[x]=min(low[x],dfn[v]);
	}

}
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define X first
#define Y second
#define nl '\n'
#define AC return 0
#define pb(a) push_back(a)
#define mst(a,b) memset(a, b, sizeof a)
#define rep(i,n) for(int i = 0; (i)<(n); i++)
#define rep1(i,n) for(int i = 1; (i)<=(n); i++)
#define scd(a) scanf("%lld", &a)
#define scdd(a,b) scanf("%lld%lld", &a, &b)
#define scs(s) scanf("%s", s)

//优先队列
priority_queue<int,vector<int>,greater<int> >q;
map<int,int>mp;
vector<int>a;
priority_queue<int>q;

/*结构体
typedef struct m{
	int income=0,number,count=0;
}a[N];

int dx[]= {1,0,-1,0},dy[]= {0,1,0,-1};
int mp[3][3];
int l,flag,n,m,x,y,dx[]= {1,0,-1,0},dy[]= {0,-1,0,1};
queue<int>q;
map<int,int>ma;

/*struct m {
	int x,y,d1,t,qx,qy;
} arr;
/*

double dist(struct p p1,struct p p2) {
	return sqrt(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2)+pow(p1.z-p2.z,2));
}

//快速幂
ll fastpow(ll x,ll y) {
	x%=mod;
	ll ans=1;
	while(y) {
		if(y&1)
			ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans%mod;
}

//滚动数组
for(int i=1; i<=n; i++)
	if(find(i)==i)
		for(int j=w; j>=cl[i].c; j--)
			ans[j]=max(ans[j],ans[j-cl[i].c]+cl[i].d);

/*void bfs() {
	while(!qx.empty()) {
		int x=qx.front();
		qx.pop();
		int y=qy.front();
		qy.pop();
		int t=qt.front();
		qt.pop();
		if(x==n&&y==n) {
			cout<<"Yes"<<endl;
			return;
		}
		for(int i=0; i<4; i++)
			if(x+dx[i]>0&&x+dx[i]<=n&&y+dy[i]>0&&y+dy[i]<=n)
				if(!b[x+dx[i]][y+dy[i]])
					if(!a[x+dx[i]][y+dy[i]]||a[x+dx[i]][y+dy[i]]>t) {
						b[x+dx[i]][y+dy[i]]=1;
						qx.push(x+dx[i]);
						qy.push(y+dy[i]);
						qt.push(t+1);
					}
	}
	cout<<"No"<<endl;
}

队列清空
void clear(queue<int>& q) {
	queue<int> empty;
	swap(empty, q);
}

约数个数
ll count(ll n) {
	l=0;
	mp.clear();
	int cnt=1;
	int i = 2;
	while (i*i<= n) {
		while (n % i == 0) {
			if (mp.find(i)==mp.end())
				mp[i]=1,a[l++]=i;
			else
				mp[i]++;
			n /= i;
		}
		i++;
	}
	if(n>1) mp[n]=1,a[l++]=n;
	for(i=0; i<l; i++)
		cnt*=mp[a[i]]+1;
	return cnt;
}

组合数
int c(int m,int n) {
	if(!m) return 1;
	int res=1;
	for(int i=n; i>n-m; i--)
		res*=i;
	for(int i=m; i>1; i++)
		res/=i;
	return res;
}

判断2进制中1的个数为奇数
int judge(ll m) {
	int count=0;
	while(m>0) {
		count++;
		m&=(m-1);
	}
	if(count&1)
		return 1;
	return 0;
}

字符串倒置
//reverse(s.begin(),s.end());

判断是否是对称数
bool reverse(int n) {
	int x=n,m=0;
	while(x) {
		m=m*10+x%10;
		x/=10;
	}
	if(m==n)
		return true;
	else
		return false;
}

int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
void join(int a,int b) {
	int fa=find(a),fb=find(b);
	if(fa!=fb)
		f[fb]=fa;
}*/
/*typedef  int  Status;
typedef  int TElemType;
typedef struct BiTNode
{
	TElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
//输入遍历序列数组
void input(TElemType a[],int n)
{
	int i;
	for(i=0;i<n;i++)
	{
		cin>>a[i];
	}
}
//输出遍历序列数组
void output(BiTree &T)
{
	queue<BiTree>q;
	q.push(T);
	cout<<T->data;
	while(!q.empty()){
		BiTree p=q.front();
		q.pop();
		if(p->lchild){
			cout<<" "<<p->lchild->data;
			q.push(p->lchild);
		}
		if(p->rchild)
		{
			cout<<" "<<p->rchild->data;
			q.push(p->rchild);
		}
	}
}
//在中序遍历序列中定位根的位置
int Locate(TElemType a[],TElemType ch,int n,int len)
{
	int i=n;
	while(i<n+len&&a[i]!= ch)
	{
		i++;
	}
	return i;
}
//已知先序中序,创建二叉树
void Create(BiTree &T,TElemType pre[],TElemType in[],int m,int n,int len)
{
	TElemType ch;
	int i,j;
	if(!len)
	{
		T=NULL;
	}
	else
	{
		ch=pre[m];
		T=(BiTree)malloc(sizeof(TElemType));
		T->data=ch;
		i=Locate(in,ch, n, len);
		j=i-n;
		Create(T->lchild,pre,in,m+1,n,j);
		Create(T->rchild,pre,in,m+j+1,i+1,len-j-1);
	}
}

void change(BiTree &T){
	if(T){
		change(T->lchild);
		change(T->rchild);
		BiTree p;
		p=T->lchild;
		T->lchild=T->rchild;
		T->rchild=p;
	}
}*/

线段树模板:


void pushup(int n) {
	t[n].ma=max(t[n<<1].ma,t[n<<1|1].ma);
	t[n].mi=min(t[n<<1].mi,t[n<<1|1].mi);
	t[n].sum=(t[n<<1].sum+t[n<<1|1].sum)%mod;
	t[n].mul=(t[n<<1].mul+t[n<<1|1].mul)%mod;
}
void build(int l,int r,int n) {
	if(l==r) {
		t[n].l=l,t[n].r=r;
		t[n].sum=t[n].mi=t[n].ma=a[l];
		t[n].mul=a[l]*a[l]%mod;
		return;
	}
	t[n].l=l,t[n].r=r;
	int mid=(l+r)>>1;
	build(l,mid,n<<1);
	build(mid+1,r,n<<1|1);
	pushup(n);
}
void update(int l,int r,int n,int pos,int val) {
	if(l==r&&l==pos) {
		t[n].sum=t[n].mi=t[n].ma=val;
		t[n].mul=val*val%mod;
		a[pos]=val;
		return;
	}
	int mid=(l+r)>>1;
	if(pos<=mid)
		update(l,mid,n<<1,pos,val);
	else
		update(mid+1,r,n<<1|1,pos,val);
	pushup(n);
}
ll ask(int l,int r,int n,ll k) {
	ll ans=0;
	if(t[n].ma<k) {
		ans=((((ll)(r-l+1)*k%mod*k%mod+t[n].mul)%mod-2ll*k%mod*t[n].sum%mod)+mod)%mod;
	} else if(t[n].ma>=k&&k>t[n].mi) {
		int mid=(l+r)>>1;
		ans=(ask(l,mid,n<<1,k)%mod+ask(mid+1,r,n<<1|1,k)%mod)%mod;
	}
	return ans%mod;
}

质数模板:

1、判断是否是质数
bool isPrime(long long n) {
	if (n <= 1) return false;
	if (n == 2 || n == 3) return true;
	if (n % 6 != 1 && n % 6 != 5) return false;
	for (long long i = 5; i * i <= n; i += 6) {
		if (n % i == 0 || n % (i + 2) == 0) return false;
	}
	return true;
}
2、埃氏筛
inline void isPrime(int n) {
	memset(book,true,n);
	for (long long i = 2; i<=n; i++) {
		if (book[i]) {
			prime[++cnt]=i;
			for (long long j = i * i; j < n; j += i) book[j] = false;
		}
	}
}
3、线性筛
inline void Prime(int n) {
	int cnt=0;
	memset(b,true,sizeof(b));
	b[0]=b[1]=0;
	for (int i = 2; i<=n; i++) {
		if (book[i]) prime[++cnt]=i;
		for (int j =1; j <= cnt&&i*prime[j]<=n; j++) {
			book[i*prime[j]] = false;
			if(i%prime[j]==0)
				break;
		}
	}
}
4、分解质因数 
vector<long long>fac;
void primeFactors(long long n) {
	fac.clear();
	long long i = 2;
	while (i * i <= n) {
		while (n % i == 0) {
			fac.push_back(i);
			n /= i;
		}
		i++;
	}
	if (n > 1)fac.push_back(n);
	for(int i=0; i<fac.size()-1; i++)printf("%lld*",fac[i]);
	printf("%lld",fac[fac.size()-1]);
}

求逆元模板:

const long long mod = 1e9 + 7;
long long fastpow(long long x, long long y) {
	x %= mod;
	long long res = 1;
	while (y) {
		if (y & 1)res = res * x % mod;
		y >>= 1;
		x = x * x % mod;
	}
	return res;
}
long long inv(long long n) {
	return fastpow(n, mod - 2)%mod;
}

组合数模板:(预处理加逆元)

long long fac[MAXN];
const long long mod = 1e9 + 7;
long long fastpow(long long x, long long y) {
	x %= mod;
	long long res = 1;
	while (y) {
		if (y & 1)res = res * x % mod;
		y >>= 1;
		x = x * x % mod;
	}
	return res;
}
void init() {
	fac[0]=1;
	for(int i=1; i<MAXN; i++)fac[i]=fac[i-1]*i%mod;
}
long long C(int n,int m) {
	return fac[m]*fastpow(fac[n],mod-2)%mod*fastpow(fac[m-n],mod-2)%mod;
}

常用库函数:

#include <algorithm> 
sort(起始地址,结束地址,排序方式)//内省式快排,无返回值 
__gcd(第一个整数,第二个整数)//返回两个整数的最大公约数 
max(第一个数,第二个数)//返回两个数中较大的那个数,min同理 
swap(第一个变量,第二个变量)//交换两个变量的值,无返回值 
unique(起始地址,结束地址)//返回址里所有不重复的变量的末尾地址,所有重复变量会排到该地址之后 
lower_bound(起始地址,结束地址,变量)//返回从起始地址到结束地址中,第一个大于等于变量的值的地址
upper_bound(起始地址,结束地址,变量)//返回从起始地址到结束地址中,第一个大于变量的值的地址 
next_permutation(起始地址,结束地址)//使地址内得到下一个全排列的组合,字典升序。 

#include <cstring> 
strlen(字符串首地址)//返回字符串长度 
memset(首地址,变量值,长度)//初始化一个数组,只建议初始化为0的时候使用 
memcpy(被拷贝数组首地址,拷贝数组首地址,长度)//拷贝一个数组 

#include <cmath> 
fabs(数字)//返回绝对值 
sqrt(数字)//返回平方根值,默认floot类型 
pow(底数,指数)//返回幂的结果 
cbrt(数字)//返回立方根。 

常用数据结构:

#include <vector> 
vector<int> arr;//创建一个int类型的向量,等价一维数组 
vector<int> arr[10];//创建10个int类型的向量,等价二维数组 
arr.push_back(变量)//往向量里添加一个变量到尾部 
arr.size()//返回向量长度,默认 long long 
arr.insert(地址,变量)//往向量规定位置添加一个变量,注意这个位置是地址 
arr.erase(地址)//删除向量里地址处变量 
arr.clear()//清空向量 
arr.begin()//返回向量首地址 
arr.end()//返回向量尾地址,是最后一个变量的下一个地址,不是最后一个变量的地址 

#include <queue> 
//先进先出 
queue<int> q;//创建一个int类型队列 
q.empty()//判断队列是否为空,是空返回true 
q.size()//返回队列长度 
q.push(变量)//往队列里添加一个变量 
q.front()//返回队列第一个变量
q.pop()//删除队列第一个变量 
priority_queue<int> q;//创建一个优先队列,默认排序从大到小,自定义排序可自学 
q.empty()//判断队列是否为空,是空返回true 
q.size()//返回队列长度 
q.push(变量)//往队列里添加一个变量 
q.top()//返回队列第一个变量 
q.pop()//删除队列第一个变量 

#include <stack> 
//先进后出 
stack<int> st;//创建一个int类型的栈堆 
st.empty()//判断栈堆是否为空,是空返回true 
q.size()//返回栈堆长度 
q.push(变量)//往栈堆里添加一个变量 
q.top()//返回栈堆第一个变量 
q.pop()//删除栈堆第一个变量 

#include <map> 
map<int,int>mp;//创建一个下标为int类型的int类型字典 
mp.count(变量)//返回下标为变量值的变量数量,与find用法类似 
mp[变量]//返回下标为变量的值,没有定义一般返回0,判断存不存在的时候效率比count低很多 

#include <unordered_map> 
unordered_map<int,int>mp;//在数据量大的时候,效率快于map 

#include <set> 
set<int> s;//创建一个int类型的集合,具有有序、不重复性 
s.size()//返回集合长度 
s.find(变量)//查找是否存在变量,不存在返回-1 
s.insert(变量)//插入一个变量,因为是有序的,不需要输入位置 
s.erase(地址)//删除地址处的变量 
//set 也有unordered_set,在大量查找的时候效率好于set 
//还有一种multiset,可重复的有序集合

Java里的高精度

import java.math.BigInteger;
import java.util.Scanner;
public class Main {
		public static void main(String[] args) {
			BigInteger a,b;
			Scanner scanner=new Scanner(System.in);
			while (scanner.hasNext()) {
				a=scanner.nextBigInteger();
				b=scanner.nextBigInteger();
				System.out.println(a.multiply(b));
			}
		}
}

矩阵快速幂:

typedef long long ll;
const int mod = 1e9 + 7;
const int MAXN = 10005;//矩阵的大小
struct Mat {
    ll m[MAXN][MAXN];
}ans, a;//ans为结果矩阵,a为输入矩阵
Mat Mul(Mat a, Mat b, int n) {//计算矩阵a乘矩阵b,n为矩阵的大小
    Mat c;//临时矩阵c
    memset(c.m, 0, sizeof(c.m));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                c.m[i][j] = (c.m[i][j] + (a.m[i][k] * b.m[k][j]) % mod) % mod;
    return c;
}
Mat _power(Mat a, int b, int n) {//计算a^b,n为矩阵的大小
    for (int i = 1; i <= n; i++)//构造单位矩阵
        ans[i][i] = 1;
    while (b) {
        if (b & 1)
            ans = Mul(ans, a, n);
        a = Mul(a, a, n);
        b >>= 1;
    }
    return ans;
}       

MST(最小生成树)模板

//Kruskal(添边法)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define N 1002
struct node {
    int u, v, w;
    node() {}
    node(int _u, int _v, int _w):u(_u), v(_v), w(_w) {}
};
vector<node> edge;
int n, m, f[N];
bool cmp(const node &x, const node &y) {
    return x.w < y.w;
}
int find_set(int x) {
    if (f[x] == x) return x;
    return f[x] = find_set(f[x]);
}

int Kruskal() {
    sort(edge.begin(), edge.end(), cmp);
    for (int i=1; i<=n; i++) f[i] = i;///将所有点加入并查集,自己是一个独立的集合
    int ans = 0;
    for (int i=0, u, v, w; i<edge.size(); i++) {///排序之后只要挨着拿就行
        u = edge[i].u, v = edge[i].v, w = edge[i].w;
        u = find_set(u), v = find_set(v);
        if (u == v) continue;
        f[u] = v;///这个是随便的,虽然会引起效率上的不稳定,但是一次路径压缩之后就都一样了..
        ans += w;
    }
    return ans;
}
int main() {
    while (scanf("%d%d", &n, &m) == 2) {
        edge.clear();
        for (int i=0, a, b, c; i<m; i++) {
            scanf("%d%d%d", &a, &b, &c);
            edge.push_back(node(a, b, c));///两端点是平等的,插入一次即可
        }
        printf("%d\n", Kruskal());
    }
    return 0;
}


//Prim(添点法)适合稠密图,即边数较多而点较少的情况,时间复杂度为O(n^2)
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
#define N 1003
#define inf 0x3f3f3f3f
struct node {
    int v, w;
    node () {}
    node(int _v, int _w) : v(_v), w(_w) {}
};
vector<node> g[N];
int n, m, d[N];
bool vis[N];

int prim() {
    memset(vis, false, sizeof(vis));
    memset(d, 0x3f, sizeof(d));
    int ans = d[1] = 0;
    for (int i=0; i<n; i++) {
        int k = 0, mi = inf;
        for (int j=1; j<=n; j++) if (!vis[j] && d[j] < mi)
            mi = d[j], k = j;
        if (k == 0) break;
        vis[k] = true;
        ans += mi;
        for (int j=0, u; j<g[k].size(); j++)
            if (!vis[u = g[k][j].v] && d[u] > g[k][j].w)
                d[u] = g[k][j].w;///和Dijkstra很像,只是这里由松弛操作改成了更新
    }///此处的d表示与树的距离
    return ans;///返回的是最小生成树的边长和
}
int main() {

    while (scanf("%d%d", &n, &m) == 2) {
        for (int i=0; i<=n; i++) g[i].clear();
        for (int i=0, a, b, c; i<m; i++) {
            scanf("%d%d%d", &a, &b, &c);
            g[a].push_back(node(b, c));
            g[b].push_back(node(a, c));
        }
        printf("%d\n", prim());
    }

    return 0;
}

求逆序对(归并排序、树状数组)

//归并排序
#include <bits/stdc++.h>
using namespace std;
int n, a[100005], tmpA[100005], cnt = 0;
void merge_sort(int l, int r, int *A) {
	if (l >= r) return ;
	int mid = (l + r) >> 1;
	merge_sort(l, mid, A);
	merge_sort(mid + 1, r, A);
	int pl = l, pr = mid + 1, tmpp = 0;
	while(pl <= mid && pr <= r) {
		if (A[pl] <= A[pr]) tmpA[tmpp++] = A[pl++];
		else tmpA[tmpp++] = A[pr++], cnt += mid - pl + 1;
	}
	while(pl <= mid) tmpA[tmpp++] = A[pl++];
	while(pr <= r) tmpA[tmpp++] = A[pr++];
	for (int i = 0; i < tmpp; i++) A[i + l] = tmpA[i];
} 
int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	merge_sort(1, n, a);
	printf("%d\n", cnt);
	return 0;
}

//树状数组
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+5;
int N;
int arr[MAXN];
long long cnt=0;
int lowbit(int x){
	return x&(-x);
} 
int getsum(int x){
	int sum=0;
	for(int i=x;i;i-=lowbit(i)) sum+=a[i];
	return sum; 
}
void update(int x){
	for(int i=x;i<=N;i+=lowbit(i)) a[i]++;
}
int main()
{
    scanf("%d",&N);
    for(int i=1;i<=N;i++)   
    update(arr[i]),cnt+=i-getsum(arr[i]);
    printf("%lld",cnt);
    return 0;
}

最大平均子序列

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5;
int arr[MAXN + 5];
double sum[MAXN + 5];
int n, m;

bool check(double avg)
{
    for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + arr[i] - avg;
    double minv = 0;
    for(int i = m; i <= n; ++i) {	
        minv = min(minv, sum[i - m]);
        if(sum[i] >= minv) return true;
    }
    return false;
}

int main()
{
    scanf("%d %d", &n, &m);  // cin  cout
    double l = 0, r = 0;
    for(int i = 1; i <= n; ++i) {
        scanf("%d", arr + i);
        r = max(r, double(arr[i]));
        l = min(l, double(arr[i]));
    }
    while(r - l > 1e-5) {//二分法
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    }

    printf("%.f\n", r);
    return 0;
}

最大子序列和

1.穷举法
算法思想:算出每个子序列的和,即算出序列中第i个到第j个数的和(j>=i),并进行比较
算法:

	public static int maxSubSum1(int[] a) {
		int maxSum = 0;
		int sum;
		for (int i = 0; i < a.length; i++) {
			for (int j = i; j < a.length; j++) {
				sum = 0;
				for (int k = i; k <= j; k++) {
					sum += a[k];// 计算a[i]到a[j]的和
				}
				if (sum > maxSum) {
					maxSum = sum;
				}
			}
		}
		return maxSum;
	}
运行时间为O(N^3)

2.对上述第一个算法的改进

算法思想:第一个算法的第三个for循环中有大量不必要的重复计算,如:计算i到j的和,然而i到j-1的和在前一次的循环中已经计算过,无需重复计算,故该for循环可以去掉
算法:
	public static int maxSubSum2(int[] a) {
		int maxSum = 0;
		int sum;
		for (int i = 0; i < a.length; i++) {
			sum = 0;
			for (int j = i; j < a.length; j++) {
				sum += a[j];
				if (sum > maxSum) {
					maxSum = sum;
				}
			}
		}
		return maxSum;
	}
运行时间为O(N^2)

3.分而治之
算法思想:把问题分成两个大致相等的子问题,然后递归地对它们求解,这是“分”的部分。“治”阶段将两个子问题的解修补到一起并可能再做些少量的附加工作,最后得到整个问题的解。

在该问题中,如果把序列从中间分为两部分,那么最大子序列和可能在三处出现,要么整个出现在输入数据的左半部,要么整个出现在右半部,要么跨越分界线。前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分(包括前半部分的最后一个元素)的最大和以及后半部分(包含后半部分的第一个元素)的最大和而得到,此时将两个和相加。

算法:
	// 参数:处理数组,左边界,右边界
	public static int maxSubSum3(int[] a, int left, int right) {
		if (left == right) {
			if (a[left] > 0) {
				return a[left];
			} else {
				return 0;
			}
		}
 
		int center = (left + right) / 2;
		int maxLeftSum = maxSubSum3(a, left, center);
		int maxRightSum = maxSubSum3(a, center + 1, right);
 
		int maxLeftBorderSum = 0, leftBorderSum = 0;
		for (int i = center; i >= left; i--) {
			leftBorderSum += a[i];
			if (leftBorderSum > maxLeftBorderSum) {
				maxLeftBorderSum = leftBorderSum;
			}
		}
 
		int maxRightBorderSum = 0, rightBorderSum = 0;
		for (int i = center + 1; i <= right; i++) {
			rightBorderSum += a[i];
			if (rightBorderSum > maxRightBorderSum) {
				maxRightBorderSum = rightBorderSum;
			}
		}
 
		int maxBorderSum = maxLeftBorderSum + maxRightBorderSum;
		return maxBorderSum > maxLeftSum ? maxBorderSum > maxRightSum ? maxBorderSum : maxRightSum
				: maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;
	}
运行时间O(N*logN)

4.最优起点
算法思想:设a[i]为和最大序列的起点,则如果a[i]是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]作为起点的子序列都可以通过a[i+1]作起点而得到改进。
类似的,任何负的子序列也不可能是最优子序列的前缀。
算法:

	public static int maxSubSum4(int[] a){
		int maxSum=0,sum=0;
		for(int i=0;i<a.length;i++){
			sum+=a[i];
			if(sum>maxSum){
				maxSum=sum;
			}else if(sum<0){
				sum=0;
			}
		}
		return maxSum;
	}
运行时间:O(N)

高精度模板

高精度加法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:倒置相加再还原。

算法复杂度:o(n)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string add(string a,string b)//只限两个非负整数相加
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
    if(na[lmax]) lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<add(a,b)<<endl;
    return 0;
}

高精度减法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:倒置相减再还原。

算法复杂度:o(n)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++)
    {
        na[i]-=nb[i];
        if(na[i]<0) na[i]+=10,na[i+1]--;
    }
    while(!na[--lmax]&&lmax>0)  ;lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<sub(a,b)<<endl;
    return 0;
}

高精度乘法

高精度乘高精度的朴素算法

算法思想:倒置相乘,然后统一处理进位,再还原。

算法复杂度:o(n^2)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
    string s;
    int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
    fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
    for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
    for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
    for(int i=1;i<=La;i++)
        for(int j=1;j<=Lb;j++)
        nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
    for(int i=1;i<=La+Lb;i++)
        nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
    if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
    for(int i=La+Lb-1;i>=1;i--)
        s+=nc[i]+'0';//将整形数组转成字符串
    return s;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<mul(a,b)<<endl;
    return 0;
}

高精度乘高精度FFT优化算法

算法思想:将两个高精度乘数每个数位上的数视为多项式对应的系数,用o(n*log(n))的复杂度转成点值形式,再利用o(n)的复杂度相乘,最后对点值进行差值,用o(n*log(n))的复杂度还原成多项式的形式,即原来的形式。

算法复杂度:o(n*log(n))
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
    int ret = 0;
    for (int i = 0; i < bits; i++)
    {
        ret <<= 1;
        ret |= x & 1;
        x >>= 1;
    }
    return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
    int bits = 0;
    while (1 << bits < n) ++bits;
    for (int i = 0; i < n; i++)
    {
        int j = revv(i, bits);
        if (i < j)
            swap(a[i], a[j]), swap(b[i], b[j]);
    }
    for (int len = 2; len <= n; len <<= 1)
    {
        int half = len >> 1;
        double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
        if (rev) wmy = -wmy;
        for (int i = 0; i < n; i += len)
        {
            double wx = 1, wy = 0;
            for (int j = 0; j < half; j++)
            {
                double cx = a[i + j], cy = b[i + j];
                double dx = a[i + j + half], dy = b[i + j + half];
                double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
                a[i + j] = cx + ex, b[i + j] = cy + ey;
                a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
                double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
                wx = wnx, wy = wny;
            }
        }
    }
    if (rev)
    {
        for (int i = 0; i < n; i++)
            a[i] /= n, b[i] /= n;
    }
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
    int len = max(na, nb), ln;
    for(ln=0; L(ln)<len; ++ln);
    len=L(++ln);
    for (int i = 0; i < len ; ++i)
    {
        if (i >= na) ax[i] = 0, ay[i] =0;
        else ax[i] = a[i], ay[i] = 0;
    }
    fft(ax, ay, len, 0);
    for (int i = 0; i < len; ++i)
    {
        if (i >= nb) bx[i] = 0, by[i] = 0;
        else bx[i] = b[i], by[i] = 0;
    }
    fft(bx, by, len, 0);
    for (int i = 0; i < len; ++i)
    {
        double cx = ax[i] * bx[i] - ay[i] * by[i];
        double cy = ax[i] * by[i] + ay[i] * bx[i];
        ax[i] = cx, ay[i] = cy;
    }
    fft(ax, ay, len, 1);
    for (int i = 0; i < len; ++i)
        ans[i] = (int)(ax[i] + 0.5);
    return len;
}
string mul(string sa,string sb)
{
    int l1,l2,l;
    int i;
    string ans;
    memset(sum, 0, sizeof(sum));
    l1 = sa.size();
    l2 = sb.size();
    for(i = 0; i < l1; i++)
        x1[i] = sa[l1 - i - 1]-'0';
    for(i = 0; i < l2; i++)
        x2[i] = sb[l2-i-1]-'0';
    l = solve(x1, l1, x2, l2, sum);
    for(i = 0; i<l || sum[i] >= 10; i++) // 进位
    {
        sum[i + 1] += sum[i] / 10;
        sum[i] %= 10;
    }
    l = i;
    while(sum[l] <= 0 && l>0)    l--; // 检索最高位
    for(i = l; i >= 0; i--)    ans+=sum[i] + '0'; // 倒序输出
    return ans;
}
int main()
{
    cin.sync_with_stdio(false);
    string a,b;
    while(cin>>a>>b) cout<<mul(a,b)<<endl;
    return 0;
}

高精度乘单精度

算法思想:倒置相乘,然后统一处理进位,再还原。

算法复杂度:o(n)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=100005;
int na[L];
string mul(string a,int b)//高精度a乘单精度b
{
    string ans;
    int La=a.size();
    fill(na,na+L,0);
    for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';
    int w=0;
    for(int i=0;i<La;i++) na[i]=na[i]*b+w,w=na[i]/10,na[i]=na[i]%10;
    while(w) na[La++]=w%10,w/=10;
    La--;
    while(La>=0) ans+=na[La--]+'0';
    return ans;
}
int main()
{
    string a;
    int b;
    while(cin>>a>>b) cout<<mul(a,b)<<endl;
    return 0;
}

高精度除法

高精度除高精度

算法思想:倒置,试商,高精度减法。

算法复杂度:o(n^2)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小于b,则返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小于b,则返回-1

    }
    for(int i=0;i<La;i++)//高精度减法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位数
    return 0;//返回差的位数

}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
    string s,v;//s存商,v存余数
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2)) {
            //cout<<0<<endl;
     return n1;}//如果a<b,则商为0,余数为被除数
     int t=La-Lb;//除被数和除数的位数之差
     for(int i=La-1;i>=0;i--)//将除数扩大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//统一处理进位
     while(!r[i]) i--;//将整形数组表示的商转化成字符串表示的
     while(i>=0) s+=r[i--]+'0';
     //cout<<s<<endl;
     i=tp;
     while(!a[i]) i--;//将整形数组表示的余数转化成字符串表示的</span>
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     //cout<<v<<endl;
     if(nn==1) return s;
     if(nn==2) return v;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<div(a,b,1)<<endl;
    return 0;
}

高精度除单精度

算法思想:模拟手工除法。

算法复杂度:o(n)
#include<iostream>
#include<algorithm>
using namespace std;
string div(string a,int b)//高精度a除以单精度b
{
    string r,ans;
    int d=0;
    if(a=="0") return a;//特判
    for(int i=0;i<a.size();i++)
    {
            r+=(d*10+a[i]-'0')/b+'0';//求出商
            d=(d*10+(a[i]-'0'))%b;//求出余数
    }
    int p=0;
    for(int i=0;i<r.size();i++)
    if(r[i]!='0') {p=i;break;}
    return r.substr(p);
}
int main()
{
    string a;
    int b;
    while(cin>>a>>b)
    {
        cout<<div(a,b)<<endl;
    }
    return 0;
}

高精度取模

高精度对高精度取模

算法思想:利用(a+b)%c=a%c+b%c。

算法复杂度:o(n)
#include<iostream>
#include<algorithm>
using namespace std;
int mod(string a,int b)//高精度a除以单精度b
{
    int d=0;
    for(int i=0;i<a.size();i++) d=(d*10+(a[i]-'0'))%b;//求出余数
    return d;
}
int main()
{
    string a;
    int b;
    while(cin>>a>>b)
    {
        cout<<mod(a,b)<<endl;
    }
    return 0;
}

高精度对单精度取模

算法思想:利用(a+b)%c=a%c+b%c。

算法复杂度:o(n)
#include<iostream>
#include<algorithm>
using namespace std;
int mod(string a,int b)//高精度a除以单精度b
{
    int d=0;
    for(int i=0;i<a.size();i++) d=(d*10+(a[i]-'0'))%b;//求出余数
    return d;
}
int main()
{
    string a;
    int b;
    while(cin>>a>>b)
    {
        cout<<mod(a,b)<<endl;
    }
    return 0;
}

高精度阶乘

算法思想:利用(a+b)%c=a%c+b%c。

算法复杂度:o(n)
#include<iostream>
#include<algorithm>
using namespace std;
int mod(string a,int b)//高精度a除以单精度b
{
    int d=0;
    for(int i=0;i<a.size();i++) d=(d*10+(a[i]-'0'))%b;//求出余数
    return d;
}
int main()
{
    string a;
    int b;
    while(cin>>a>>b)
    {
        cout<<mod(a,b)<<endl;
    }
    return 0;
}

高精度幂

算法思想:FFT高精乘+二分求幂。

算法复杂度:o(n*log(n)*log(m))
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
    int ret = 0;
    for (int i = 0; i < bits; i++)
    {
        ret <<= 1;
        ret |= x & 1;
        x >>= 1;
    }
    return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
    int bits = 0;
    while (1 << bits < n) ++bits;
    for (int i = 0; i < n; i++)
    {
        int j = revv(i, bits);
        if (i < j)
            swap(a[i], a[j]), swap(b[i], b[j]);
    }
    for (int len = 2; len <= n; len <<= 1)
    {
        int half = len >> 1;
        double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
        if (rev) wmy = -wmy;
        for (int i = 0; i < n; i += len)
        {
            double wx = 1, wy = 0;
            for (int j = 0; j < half; j++)
            {
                double cx = a[i + j], cy = b[i + j];
                double dx = a[i + j + half], dy = b[i + j + half];
                double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
                a[i + j] = cx + ex, b[i + j] = cy + ey;
                a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
                double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
                wx = wnx, wy = wny;
            }
        }
    }
    if (rev)
    {
        for (int i = 0; i < n; i++)
            a[i] /= n, b[i] /= n;
    }
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
    int len = max(na, nb), ln;
    for(ln=0; L(ln)<len; ++ln);
    len=L(++ln);
    for (int i = 0; i < len ; ++i)
    {
        if (i >= na) ax[i] = 0, ay[i] =0;
        else ax[i] = a[i], ay[i] = 0;
    }
    fft(ax, ay, len, 0);
    for (int i = 0; i < len; ++i)
    {
        if (i >= nb) bx[i] = 0, by[i] = 0;
        else bx[i] = b[i], by[i] = 0;
    }
    fft(bx, by, len, 0);
    for (int i = 0; i < len; ++i)
    {
        double cx = ax[i] * bx[i] - ay[i] * by[i];
        double cy = ax[i] * by[i] + ay[i] * bx[i];
        ax[i] = cx, ay[i] = cy;
    }
    fft(ax, ay, len, 1);
    for (int i = 0; i < len; ++i)
        ans[i] = (int)(ax[i] + 0.5);
    return len;
}
string mul(string sa,string sb)
{
    int l1,l2,l;
    int i;
    string ans;
    memset(sum, 0, sizeof(sum));
    l1 = sa.size();
    l2 = sb.size();
    for(i = 0; i < l1; i++)
        x1[i] = sa[l1 - i - 1]-'0';
    for(i = 0; i < l2; i++)
        x2[i] = sb[l2-i-1]-'0';
    l = solve(x1, l1, x2, l2, sum);
    for(i = 0; i<l || sum[i] >= 10; i++) // 进位
    {
        sum[i + 1] += sum[i] / 10;
        sum[i] %= 10;
    }
    l = i;
    while(sum[l] <= 0 && l>0)    l--; // 检索最高位
    for(i = l; i >= 0; i--)    ans+=sum[i] + '0'; // 倒序输出
    return ans;
}
string Pow(string a,int n)
{
    if(n==1) return a;
    if(n&1) return mul(Pow(a,n-1),a);
    string ans=Pow(a,n/2);
    return mul(ans,ans);
}
int main()
{
    cin.sync_with_stdio(false);
    string a;
    int b;
    while(cin>>a>>b) cout<<Pow(a,b)<<endl;
    return 0;
}

高精度GCD

算法思想:高精度加减乘除的运用。

算法复杂度:已无法估计。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int L=110;
string add(string a,string b)
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
    if(na[lmax]) lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
string mul(string a,string b)
{
    string s;
    int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
    fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
    for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
    for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
    for(int i=1;i<=La;i++)
        for(int j=1;j<=Lb;j++)
        nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
    for(int i=1;i<=La+Lb;i++)
        nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
    if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
    for(int i=La+Lb-1;i>=1;i--)
        s+=nc[i]+'0';//将整形数组转成字符串
    return s;
}
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小于b,则返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小于b,则返回-1

    }
    for(int i=0;i<La;i++)//高精度减法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位数
    return 0;//返回差的位数

}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
    string s,v;//s存商,v存余数
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2)) {
            //cout<<0<<endl;
     return n1;}//如果a<b,则商为0,余数为被除数
     int t=La-Lb;//除被数和除数的位数之差
     for(int i=La-1;i>=0;i--)//将除数扩大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//统一处理进位
     while(!r[i]) i--;//将整形数组表示的商转化成字符串表示的
     while(i>=0) s+=r[i--]+'0';
     //cout<<s<<endl;
     i=tp;
     while(!a[i]) i--;//将整形数组表示的余数转化成字符串表示的</span>
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     //cout<<v<<endl;
     if(nn==1) return s;
     if(nn==2) return v;
}
bool judge(string s)//判断s是否为全0串
{
    for(int i=0;i<s.size();i++)
        if(s[i]!='0') return false;
    return true;
}
string gcd(string a,string b)//求最大公约数
{
    string t;
    while(!judge(b))//如果余数不为0,继续除
    {
        t=a;//保存被除数的值
        a=b;//用除数替换被除数
        b=div(t,b,2);//用余数替换除数
    }
    return a;
}
int main()
{
    cin.sync_with_stdio(false);
    string a,b;
    while(cin>>a>>b) cout<<gcd(a,b)<<endl;
    return 0;
}

高精度进制转换

算法思想:模拟手工进制转换。

算法复杂度:o(n^2)#include<iostream>
#include<algorithm>
using namespace std;
//将字符串表示的10进制大整数转换为m进制的大整数
//并返回m进制大整数的字符串
bool judge(string s)//判断串是否为全零串
{
    for(int i=0;i<s.size();i++)
        if(s[i]!='0') return 1;
    return 0;
}
string solve(string s,int n,int m)//n进制转m进制只限0-9进制,若涉及带字母的进制,稍作修改即可
{
    string r,ans;
    int d=0;
    if(!judge(s)) return "0";//特判
    while(judge(s))//被除数不为0则继续
    {
        for(int i=0;i<s.size();i++)
        {
            r+=(d*n+s[i]-'0')/m+'0';//求出商
            d=(d*n+(s[i]-'0'))%m;//求出余数
        }
       s=r;//把商赋给下一次的被除数
       r="";//把商清空
        ans+=d+'0';//加上进制转换后数字
        d=0;//清空余数
    }
    reverse(ans.begin(),ans.end());//倒置下
    return ans;
}
int main()
{
    string s;
    while(cin>>s)
    {
        cout<<solve(s,10,7)<<endl;
    }
    return 0;
}

高精度求平方根

思路就是二分+高精度加减乘除法

设数的长度为n,则需二分log(2,10^n)次即n*log(2,10) 约等于n*3.3,由于数的长度为n,朴素高精度乘法复杂度为o(n^2)。故朴素算法求解高精度平方根复杂度为O(n^3)

当然,你也可以用FFT优化下高精度乘法。

下面的代码实现了求大整数平方根的整数部分。

JAVA版

import java.io.*;
import java.math.*;
import java.util.*;
public class Main {
	static Scanner cin = new Scanner (new BufferedInputStream(System.in));
	public static BigInteger BigIntegerSqrt(BigInteger n){
		BigInteger l=BigInteger.ONE,r=n,mid,ans=BigInteger.ONE;
		while(l.compareTo(r)<=0){
			mid=l.add(r).divide(BigInteger.valueOf(2));
			if(mid.multiply(mid).compareTo(n)<=0){
				ans=mid;
				l=mid.add(BigInteger.ONE);
			}else{
				r=mid.subtract(BigInteger.ONE);
			}
		}
		return ans;
	}
	public static void main(String args []){
		BigInteger n;
		int t;
		t= cin.nextInt();
		while(t > 0)
		{
			t--;
			n=cin.nextBigInteger();
			BigInteger ans=BigIntegerSqrt(n);
			System.out.println(ans);
		}
	}
}


C++#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int L=2015;
string add(string a,string b)//只限两个非负整数相加
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
    if(na[lmax]) lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++)
    {
        na[i]-=nb[i];
        if(na[i]<0) na[i]+=10,na[i+1]--;
    }
    while(!na[--lmax]&&lmax>0)  ;lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
    string s;
    int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
    fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
    for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
    for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
    for(int i=1;i<=La;i++)
        for(int j=1;j<=Lb;j++)
        nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
    for(int i=1;i<=La+Lb;i++)
        nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
    if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
    for(int i=La+Lb-1;i>=1;i--)
        s+=nc[i]+'0';//将整形数组转成字符串
    return s;
}
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小于b,则返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小于b,则返回-1

    }
    for(int i=0;i<La;i++)//高精度减法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位数
    return 0;//返回差的位数

}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
    string s,v;//s存商,v存余数
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2)) {
            //cout<<0<<endl;
     return n1;}//如果a<b,则商为0,余数为被除数
     int t=La-Lb;//除被数和除数的位数之差
     for(int i=La-1;i>=0;i--)//将除数扩大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//统一处理进位
     while(!r[i]) i--;//将整形数组表示的商转化成字符串表示的
     while(i>=0) s+=r[i--]+'0';
     //cout<<s<<endl;
     i=tp;
     while(!a[i]) i--;//将整形数组表示的余数转化成字符串表示的</span>
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     //cout<<v<<endl;
     if(nn==1) return s;
     if(nn==2) return v;
}
bool cmp(string a,string b)
{
    if(a.size()<b.size()) return 1;//a小于等于b返回真
    if(a.size()==b.size()&&a<=b) return 1;
    return 0;
}
string BigInterSqrt(string n)
{
    string l="1",r=n,mid,ans;
    while(cmp(l,r))
    {
        mid=div(add(l,r),"2",1);
        if(cmp(mul(mid,mid),n)) ans=mid,l=add(mid,"1");
        else r=sub(mid,"1");
    }
    return ans;
}
string DeletePreZero(string s)
{
    int i;
    for(i=0;i<s.size();i++)
        if(s[i]!='0') break;
    return s.substr(i);
}
int main()
{
     //freopen("in.txt","r",stdin);
   //  freopen("out.txt","w",stdout);
    string n;
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        n=DeletePreZero(n);
        cout<<BigInterSqrt(n)<<endl;
        //cout<<BigInterSqrt(n).size()<<endl;
    }
    return 0;
}
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An<O(N), O(1)> algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
1 图论 3 1.1 术语 3 1.2 独立集、覆盖集、支配集之间关系 3 1.3 DFS 4 1.3.1 割顶 6 1.3.2 桥 7 1.3.3 强连通分量 7 1.4 最小点基 7 1.5 拓扑排序 7 1.6 欧拉路 8 1.7 哈密顿路(正确?) 9 1.8 Bellman-ford 9 1.9 差分约束系统(用bellman-ford解) 10 1.10 dag最短路径 10 1.11 二分图匹配 11 1.11.1 匈牙利算法 11 1.11.2 KM算法 12 1.12 网络流 15 1.12.1 最大流 15 1.12.2 上下界的网络的最大流 17 1.12.3 上下界的网络的最小流 17 1.12.4 最小费用最大流 18 1.12.5 上下界的网络的最小费用最小流 21 2 数论 21 2.1 最大公约数gcd 21 2.2 最小公倍数lcm 22 2.3 快速幂取模B^LmodP(O(logb)) 22 2.4 Fermat小定理 22 2.5 Rabin-Miller伪素数测试 22 2.6 Pollard-rho 22 2.7 扩展欧几里德算法extended-gcd 24 2.8 欧拉定理 24 2.9 线性同余方程ax≡b(mod n) 24 2.10 中国剩余定理 25 2.11 Discrete Logging(BL == N (mod P)) 26 2.12 N!最后一个不为0的数字 27 2.13 2^14以内的素数 27 3 数据结构 31 3.1 堆(最小堆) 31 3.1.1 删除最小值元素: 31 3.1.2 插入元素和向上调整: 32 3.1.3 堆的建立 32 3.2 并查集 32 3.3 树状数组 33 3.3.1 LOWBIT 33 3.3.2 修改a[p] 33 3.3.3 前缀和A[1]+…+A[p] 34 3.3.4 一个二维树状数组的程序 34 3.4 线段树 35 3.5 字符串 38 3.5.1 字符串哈希 38 3.5.2 KMP算法 40 4 计算几何 41 4.1 直线交点 41 4.2 判断线段相交 41 4.3 三点外接圆圆心 42 4.4 判断点在多边形内 43 4.5 两圆交面积 43 4.6 最小包围圆 44 4.7 经纬度坐标 46 4.8 凸包 46 5 Problem 48 5.1 RMQ-LCA 48 5.1.1 Range Minimum Query(RMQ) 49 5.1.2 Lowest Common Ancestor (LCA) 53 5.1.3 Reduction from LCA to RMQ 56 5.1.4 From RMQ to LCA 57 5.1.5 An algorithm for the restricted RMQ 60 5.1.6 An AC programme 61 5.2 最长公共子序列LCS 64 5.3 最长上升子序列/最长不下降子序列(LIS) 65 5.3.1 O(n^2) 65 5.3.2 O(nlogn) 66 5.4 Joseph问题 67 5.5 0/1背包问题 68 6 组合数学相关 69 6.1 The Number of the Same BST 69 6.2 排列生成 71 6.3 逆序 72 6.3.1 归并排序求逆序 72 7 数值分析 72 7.1 二分法 72 7.2 迭代法(x=f(x)) 73 7.3 牛顿迭代 74 7.4 数值积分 74 7.5 高斯消元 75 8 其它 77
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值