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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值