各类模板(更新中...)(若有什么特别的需要,可以留下评论)
Posted queuelovestack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了各类模板(更新中...)(若有什么特别的需要,可以留下评论)相关的知识,希望对你有一定的参考价值。
后缀数组(DC3算法,时间复杂度O(n))
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[MAXN],wb[MAXN],wv[MAXN],ws_[MAXN];
int c0(int *r,int a,int b)
return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];
int c12(int k,int *r,int a,int b)
if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];
void sort(int *r,int *a,int *b,int n,int m)
int i;
for(i=0; i<n; i++) wv[i]=r[a[i]];
for(i=0; i<m; i++) ws_[i]=0;
for(i=0; i<n; i++) ws_[wv[i]]++;
for(i=1; i<m; i++) ws_[i]+=ws_[i-1];
for(i=n-1; i>=0; i--) b[--ws_[wv[i]]]=a[i];
return;
void dc3(int *r,int *sa,int n,int m)
int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
r[n]=r[n+1]=0;
for(i=0; i<n; i++) if(i%3!=0) wa[tbc++]=i;
sort(r+2,wa,wb,tbc,m);
sort(r+1,wb,wa,tbc,m);
sort(r,wa,wb,tbc,m);
for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)
rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
if(p<tbc) dc3(rn,san,tbc,p);
else for(i=0; i<tbc; i++) san[rn[i]]=i;
for(i=0; i<tbc; i++) if(san[i]<tb) wb[ta++]=san[i]*3;
if(n%3==1) wb[ta++]=n-1;
sort(r,wb,wa,ta,m);
for(i=0; i<tbc; i++) wv[wb[i]=G(san[i])]=i;
for(i=0,j=0,p=0; i<ta && j<tbc; p++)
sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
for(; i<ta; p++) sa[p]=wa[i++];
for(; j<tbc; p++) sa[p]=wb[j++];
//各个参数的作用和前面的倍增算法一样,不同的地方是r数组和sa数组的
//大小都要是3*n,这为了方便下面的递归处理,不用每次都申请新的内存空间
int Rank[MAXN], height[MAXN], sa[3*MAXN], r[3*MAXN];
void calheight(int *r,int *sa,int n)
int i,j,k=0;
for(i=1; i<=n; i++)Rank[sa[i]]=i;
for(i=0; i<n; height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
后缀数组(倍增算法,时间复杂度O(nlogn))
const int MAXN = 100010;
//rnk从0开始
//sa从1开始,因为最后一个字符(最小的)排在第0位
//height从1开始,因为表示的是sa[i - 1]和sa[i]
//倍增算法 O(nlogn)
int wa[MAXN], wb[MAXN], wv[MAXN], ws_[MAXN];
//Suffix函数的参数m代表字符串中字符的取值范围,是基数排序的一个参数,如果原序列都是字母可以直接取128,如果原序列本身都是整数的话,则m可以取比最大的整数大1的值
//待排序的字符串放在r数组中,从r[0]到r[n-1],长度为n
//为了方便比较大小,可以在字符串后面添加一个字符,这个字符没有在前面的字符中出现过,而且比前面的字符都要小
//同上,为了函数操作的方便,约定除r[n-1]外所有的r[i]都大于0,r[n-1]=0
//函数结束后,结果放在sa数组中,从sa[0]到sa[n-1]
void Suffix(int *r, int *sa, int n, int m)
int i, j, k, *x = wa, *y = wb, *t;
//对长度为1的字符串排序
//一般来说,在字符串的题目中,r的最大值不会很大,所以这里使用了基数排序
//如果r的最大值很大,那么把这段代码改成快速排序
for(i = 0; i < m; ++i) ws_[i] = 0;
for(i = 0; i < n; ++i) ws_[x[i] = r[i]]++;//统计字符的个数
for(i = 1; i < m; ++i) ws_[i] += ws_[i - 1];//统计不大于字符i的字符个数
for(i = n - 1; i >= 0; --i) sa[--ws_[x[i]]] = i;//计算字符排名
//基数排序
//x数组保存的值相当于是rank值
for(j = 1, k = 1; k < n; j *= 2, m = k)
//j是当前字符串的长度,数组y保存的是对第二关键字排序的结果
//第二关键字排序
for(k = 0, i = n - j; i < n; ++i) y[k++] = i;//第二关键字为0的排在前面
for(i = 0; i < n; ++i) if(sa[i] >= j) y[k++] = sa[i] - j;//长度为j的子串sa[i]应该是长度为2 * j的子串sa[i] - j的后缀(第二关键字),对所有的长度为2 * j的子串根据第二关键字来排序
for(i = 0; i < n; ++i) wv[i] = x[y[i]];//提取第一关键字
//按第一关键字排序 (原理同对长度为1的字符串排序)
for(i = 0; i < m; ++i) ws_[i] = 0;
for(i = 0; i < n; ++i) ws_[wv[i]]++;
for(i = 1; i < m; ++i) ws_[i] += ws_[i - 1];
for(i = n - 1; i >= 0; --i) sa[--ws_[wv[i]]] = y[i];//按第一关键字,计算出了长度为2 * j的子串排名情况
//此时数组x是长度为j的子串的排名情况,数组y仍是根据第二关键字排序后的结果
//计算长度为2 * j的子串的排名情况,保存到数组x
t = x;
x = y;
y = t;
for(x[sa[0]] = 0, i = k = 1; i < n; ++i)
x[sa[i]] = (y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j]) ? k - 1 : k++;
//若长度为2 * j的子串sa[i]与sa[i - 1]完全相同,则他们有相同的排名
int Rank[MAXN], height[MAXN], sa[MAXN], r[MAXN];
void calheight(int *r,int *sa,int n)
int i,j,k=0;
for(i=1; i<=n; i++)Rank[sa[i]]=i;
for(i=0; i<n; height[Rank[i++]]=k)
for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
int main()
int n,i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&r[i]);
Max=max(Max,r[i]);
r[i]=0;
Suffix(r,sa,n+1,Max+1);
calheight(r,sa,n);
return 0;
简单多边形面积交(简单多边形面积并=简单多边形面积和-简单多边形面积交)
/*Sherlock and Watson and Adler*/
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define eps 1e-9
using namespace std;
const int N = 105;
struct point
double x,y;
point()x = y = 0;
point(double a, double b)
x = a, y = b;
inline point operator-(const point &b)const
return point(x - b.x, y - b.y);
inline point operator+(const point &b)const
return point(x + b.x, y + b.y);
inline double dot(const point &b)const
return x * b.x + y * b.y;
inline double cross(const point &b, const point &c)const
return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);
a[N],b[N];
int dcmp(double x)
if(x > eps) return 1;
return x < -eps ? -1 : 0;
point LineCross(const point &a, const point &b, const point &c, const point &d)
double u = a.cross(b, c), v = b.cross(a, d);
return point((c.x * v + d.x * u) / (u + v), (c.y * v + d.y * u) / (u + v));
double PolygonArea(point p[], int n)
if(n < 3) return 0.0;
double s = p[0].y * (p[n - 1].x - p[1].x);
p[n] = p[0];
for(int i = 1; i < n; ++ i)
s += p[i].y * (p[i - 1].x - p[i + 1].x);
return fabs(s * 0.5);
double CPIA(point a[], point b[], int na, int nb)//ConvexPolygonIntersectArea
point p[10], tmp[10];
int i, j, tn, sflag, eflag;
a[na] = a[0], b[nb] = b[0];
memcpy(p, b, sizeof(point) * (nb + 1));
for(i = 0; i < na && nb > 2; ++ i)
sflag = dcmp(a[i].cross(a[i + 1], p[0]));
for(j = tn = 0; j < nb; ++ j, sflag = eflag)
if(sflag >= 0) tmp[tn ++] = p[j];
eflag = dcmp(a[i].cross(a[i + 1], p[j + 1]));
if((sflag ^ eflag) == -2)
tmp[tn ++] = LineCross(a[i], a[i + 1], p[j], p[j + 1]);
memcpy(p, tmp, sizeof(point) * tn);
nb = tn, p[nb] = p[0];
if(nb < 3) return 0.0;
return PolygonArea(p, nb);
double SPIA(point a[], point b[], int na, int nb)//SimplePolygonIntersectArea
int i, j;
point t1[4], t2[4];
double res = 0, if_clock_t1, if_clock_t2;
a[na] = t1[0] = a[0], b[nb] = t2[0] = b[0];
for(i = 2; i < na; ++ i)
t1[1] = a[i - 1], t1[2] = a[i];
if_clock_t1 = dcmp(t1[0].cross(t1[1], t1[2]));
if(if_clock_t1 < 0) std::swap(t1[1], t1[2]);
for(j = 2; j < nb; ++ j)
t2[1] = b[j - 1], t2[2] = b[j];
if_clock_t2 = dcmp(t2[0].cross(t2[1], t2[2]));
if(if_clock_t2 < 0) std::swap(t2[1], t2[2]);
res += CPIA(t1, t2, 3, 3) * if_clock_t1 * if_clock_t2;
return res;
int main()
int n,m,i,p=1;
while(~scanf("%d",&n))
for(i=0;i<n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);
scanf("%d",&m);
for(i=0;i<m;i++)
scanf("%lf%lf",&b[i].x,&b[i].y);
printf("%.8f\\n",fabs(SPIA(a,b,n,m)));
return 0;
中国剩余定理模板(求解一元模线性方程组)
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 105;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int group;
LL n[N],a[N];
LL Egcd(LL a,LL b,LL &x,LL &y)
if(b==0)
x=1,y=0;
return a;
LL d,tp;
d=Egcd(b,a%b,x,y);
tp=x;
x=y;
y=tp-a/b*y;
return d;
LL solve()
int i;
bool flag = false;
LL n1 = n[0], n2, b1 = a[0], b2, bb, d, t, k, x, y;
for (i = 1; i < group; i++)
n2 = n[i], b2 = a[i];
bb = b2 - b1;
d = Egcd (n1, n2, x, y);
if (bb % d) //模线性解k1时发现无解
flag = true;
break;
k = bb / d * x; //相当于求上面所说的k1【模线性方程】
t = n2 / d;
if (t < 0) t = -t;
k = (k % t + t) % t; //相当于求上面的K`
b1 = b1 + n1*k;
n1 = n1 / d * n2;
if(flag)
return -1; //无解
/******************求正整数解******************/
if(b1==0) //如果解为0,而题目要正整数解,显然不行
b1=n1; //n1刚好为所有ni的最小公倍数,就是解了
/******************求正整数解******************/
return b1; //形成的解:b1, b1+n1, b1+2n1,..., b1+xni...
int main()
int i;
scanf("%d",&group);
for(i=0;i<group;i++)
//X mod n[i] = a[i] ,n[i]两两之间不一定互质做法
scanf ("%lld%lld",&n[i],&a[i]);
a[i]%=n[i];
printf ("%lld\\n",solve());
return 0;
STL全排列函数
bool next_permutation(begin,end);
二分图匹配之最大匹配(匈牙利算法)
int l,r,link[N];//l为左集合点数,r为右集合点数
bool v[N],g[N][N];//编号为0~n-1
bool dfs(int u)
int i;
for(i=0;i<r;i++)
if(g[u][i]&&!v[i])
v[i]=true;
if(link[i]==-1||dfs(link[i]))
link[i]=u;
return true;
return false;
int hungary()
int i,res=0;
memset(link,-1,sizeof(link));
for(i=0;i<l;i++)
memset(v,false,sizeof(v));
if(dfs(i))
res++;
return res;
树上任意两点距离之和的平均数
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct edge
int v,to,x;
e[2*N];
int h[M],p;
__int64 n;
void add_edge(int u,int v,int x)
e[p].v=v;
e[p].x=x;
e[p].to=h[u];
h[u]=p++;
double dp[M];
__int64 sum[M];
void dfs(int root,int father)
sum[root]=1;
for(int i=h[root];i+1;i=e[i].to)
int son=e[i].v;
int len=e[i].x;
if(son==father)
continue;
dfs(son,root);
sum[root]+=sum[son];
dp[root]+=dp[son]+(sum[son]*(n-sum[son]))*(double)len;
int main()
p=0;
memset(h,-1,sizeof(h));
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
scanf("%I64d",&n);
/*建树*/
dfs(1,-1);//点为1~n
__int64 s=(n*(n-1)/2);
printf("%.2f\\n",dp[1]/s);
return 0;
最小生成树prim邻接表实现(时间复杂度O(elogn))
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
struct edge
int v,to,x;
e[2*N],w[M*2];
bool v[M];
int h[M],p,k,l[M];
__int64 n;
struct node
int u,v,d;
bool operator < (const node &a) const
return d>a.d;//最小值优先
node()
node(int _u,int _v,int _d):u(_u),v(_v),d(_d)
;
void add_edge(int u,int v,int x)
e[p].v=v;
e[p].x=x;
e[p].to=h[u];
h[u]=p++;
void add_newedge(int u,int v,int x)
w[k].v=v;
w[k].x=x;
w[k].to=l[u];
l[u]=k++;
int main()
int t,i,m,a,b,c;
__int64 ans;
node u;
priority_queue<node> q;
scanf("%d",&t);
while(t--)
k=p=0;ans=0;
while(!q.empty())
q.pop();
scanf("%I64d%d",&n,&m);
for(i=1;i<=n;i++)
h[i]=-1;
l[i]=-1;
v[i]=false;
for(i=0;i<m;i++)
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
for(i=h[1];i+1;i=e[i].to)
q.push(node(1,e[i].v,e[i].x));
v[1]=true;
while(!q.empty())
u=q.top();
q.pop();
if(v[u.v])
continue;
ans+=u.d;
add_newedge(u.u,u.v,u.d);
add_newedge(u.v,u.u,u.d);
v[u.v]=true;
for(i=h[u.v];i+1;i=e[i].to)
if(!v[e[i].v])
q.push(node(u.v,e[i].v,e[i].x));
printf("%I64d\\n",ans);
return 0;
矩阵乘法
对于线性递推式,例如f(n)=2f(n-4)-3f(n-2)+4f(n-1),其对应矩阵的构造方法为:在右上角的(n-1)*(n-1)的小矩阵中的主对角线上填1,矩阵第n行填对应的系数,其它地方都填0
const int N = 2;
const int M = 40;
const int inf = 1000000007;
const int mod = 1000000007;
typedef struct node
__int64 a[N][N];
void Init()
memset(a,0,sizeof(a));
for(int i=0;i<N;i++)
a[i][i]=1;
matrix;
matrix mul(matrix a,matrix b)//矩阵乘法
matrix ans;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
ans.a[i][j]=0;
for(int k=0;k<N;k++)
ans.a[i][j]+=(a.a[i][k]*b.a[k][j])%mod;
ans.a[i][j]%=mod;
return ans;
matrix add(matrix a,matrix b)//矩阵加法
matrix ans;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
ans.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
return ans;
matrix pow(matrix a,int n)//求a^n
matrix ans;
ans.Init();
while(n)
if(n%2)
ans=mul(ans,a);
n/=2;
a=mul(a,a);
return ans;
StoerWagner算法(无向图全局最小割 时间复杂度O(n^3) 选定一个源点s和一个汇点t,求最大流最小)
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 305;
const int M = 10005;
const int mod = 1000000007;
const int inf = 100000007;
int Map[N][N];
int v[N], dis[N];
bool vis[N];
int StoerWagner(int n)
int i,j,res=inf;
for(i=0;i<n;i++)
v[i]=i;
while(n>1)
int k=1,pre=0;
for(i=1;i<n;i++)
dis[v[i]]=Map[v[0]][v[i]];
if(dis[v[i]]>dis[v[k]])
k=i;
memset(vis,0,sizeof(vis));
vis[v[0]]=true;
for(i=1;i<n;i++)
if(i==n-1)
res=min(res,dis[v[k]]);
for(j=0;j<n;j++)
Map[v[pre]][v[j]] += Map[v[j]][v[k]];
Map[v[j]][v[pre]] += Map[v[j]][v[k]];
v[k] = v[-- n];
vis[v[k]] = true;
pre = k;
k = -1;
for(j = 1; j < n; j ++)
if(!vis[v[j]])
dis[v[j]] += Map[v[pre]][v[j]];
if(k == -1 || dis[v[k]] < dis[v[j]])
k = j;
return res;
int main()
int n,m,u,v,w,s,i;
while(scanf("%d%d%d",&n,&m,&s)&&(n||m||s))
memset(Map,0,sizeof(Map));
for(i=0;i<m;i++)
scanf("%d%d%d",&u,&v,&w);
Map[u-1][v-1]+=w;
Map[v-1][u-1]+=w;
printf("%d\\n",StoerWagner(n));
return 0;
AC自动机(多模式匹配)
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 1000005;
const int M = 1001;
const int mod = 1000000007;
const int inf = 100000007;
char keyword[M];//输入的一系列模式串
char s[N];//长串
int ans;
struct node
int val;//是否为该单词的最后一个节点
node *next[26];//Tire每个节点的子节点个数
node *fail;//失败指针
node()//构造函数初始化
val = 0;
for(int i = 0; i < 26; i++)
next[i] = NULL;
fail = NULL;
;
node *root;
void insert(char *s)//构造前缀树
int n = strlen(s);
node *curr = root;
for(int i = 0; i < n; i++)
int c = s[i] - 'A';
if(curr->next[c] == NULL)
curr->next[c] = new node;
curr = curr->next[c];
curr->val++;//在单词的最后一个节点val+1,代表一个单词
void build()//用bfs为每个节点设定fail指针
int i;
node *temp,*p;
root->fail = NULL;//root的失败指针指向自己或者NULL
queue <node*> Q;
Q.push(root);//把root加入队列
while(!Q.empty())
temp = Q.front();
Q.pop();
for(i = 0; i < 26; i++)
if(temp->next[i] == NULL)
continue;
if(temp == root)
temp->next[i]->fail = root;
else
p = temp->fail;//p指向h节点所指的节点,也就是root
while(p != NULL)
if(p->next[i] != NULL)
temp->next[i]->fail = p->next[i];
break;
p = p->fail;
if(p == NULL)
temp->next[i]->fail = root;
Q.push(temp->next[i]);
void find(char *s)
int n = strlen(s);
node *p = root;
for(int i = 0; i < n; i++)
int c = s[i] - 'A';//c=0~25
while(p != root && p->next[c] == NULL)
p = p->fail;//p指向p的失败指针所指向的节点
p = p->next[c];//p指向c节点
if(p == NULL)
p = root;
node *temp = p;
while(temp != root&&temp->val!=-1)
ans += temp->val;
temp->val = -1;//将val信息置为-1,表示已经出现过
temp = temp->fail;//temp指向e的失败指针所指向的节点继续查找
void del(node *p)//不同题不同的查询
for(int i = 0; i < 26; i++)
if(p->next[i] != NULL)
del(p->next[i]);
free(p);
int main()//假设有N个模式,平均长度为L;文章长度为M。建立Trie树:O(N*L) 建立fail指针:O(N*L) 模式匹配:O(M*L) 所以,总时间复杂度为:O((N+M)*L)
int t;
scanf("%d", &t);
while(t--)
ans = 0;
root = new node;
int n;
scanf("%d",&n);
while(n--)
scanf("%s",keyword);
insert(keyword);
build();
scanf("%s",s);
find(s);
//del(root);/*杭电G++提交的时候如果不释放可能会MLE,而FZU、POJ等释放可能会TLE,视情况而定*/
printf("%d\\n",ans);
return 0;
2-SAT算法判可行性模板(时间复杂度O(m))
struct edge
int to,next;
e[10*M];
int n,p,k,h[N],dfn[N],low[N],belong[N],ans;
bool instack[N];
stack<int> s;
void add_edge(int u,int v)
e[p].to=v;
e[p].next=h[u];
h[u]=p++;
void Clear()
ans=k=p=0;
while(!s.empty())
s.pop();
memset(h,-1,sizeof(h));
memset(instack,false,sizeof(instack));
memset(dfn,0,sizeof(dfn));
memset(belong,0,sizeof(belong));
void Tarjan(int u)
int i,v,Top;
dfn[u]=low[u]=++k;
s.push(u);
instack[u]=true;
for(i=h[u];i+1;i=e[i].next)
v=e[i].to;
if(!dfn[v])
Tarjan(v);
low[u]=min(low[u],low[v]);
else if(instack[v])
low[u]=min(dfn[v],low[u]);
if(low[u]==dfn[u])
ans++;
while(!s.empty())
Top=s.top();
s.pop();
belong[Top]=ans;
instack[Top]=false;
if(Top==u)
break;
int a[M],b[M],c[M];
void mapping(int x)
//建图,根据题目来,边的含义为"必须"
for(int i=0;i<=x;i++)
if(c[i]==2)
add_edge(a[i]+n,b[i]);
add_edge(b[i]+n,a[i]);
else if(c[i]==1)
add_edge(a[i],b[i]);
add_edge(b[i],a[i]);
add_edge(a[i]+n,b[i]+n);
add_edge(b[i]+n,a[i]+n);
else
add_edge(a[i],b[i]+n);
add_edge(b[i],a[i]+n);
bool judge(int x)
int i;
Clear();
mapping(x);
for(i=0;i<2*n;i++)
if(!dfn[i])
Tarjan(i);
for(i=0;i<n;i++)
if(belong[i]==belong[i+n])
return false;
return true;
KM算法模板(求解带权二分图最优匹配)
int g[N][N];//主函数里建图
int lx[N],ly[N];
int match[N];
bool visx[N],visy[N];
int slack[N];
bool dfs(int cur,int n)
visx[cur]=true;
for(int y=1;y<=n;y++)
if(visy[y])
continue;
int t=lx[cur]+ly[y]-g[cur][y];
if(!t)
visy[y]=true;
if(match[y]==-1||dfs(match[y],n))
match[y]=cur;
return true;
else if(slack[y]>t)
slack[y]=t;
return false;
int KM(int n)//时间复杂度O(n^3) 实现带权二分图匹配
//两个集合的点数均为n,点数不相同可以通过补点加0边实现转化
memset(match,-1,sizeof(match));
memset(ly,0,sizeof(ly));
for(int i=1;i<=n;i++)
lx[i]=-inf;
for(int j=1;j<=n;j++)
if(g[i][j]>lx[i])
lx[i]=g[i][j];
for(int x=1;x<=n;x++)
for(int i=1;i<=n;i++)
slack[i]=inf;
while(1)
memset(visx,false,sizeof(visx));
memset(visy,false,sizeof(visy));
if(dfs(x,n))
break;
int d=inf;
for(int i=1;i<=n;i++)
if(!visy[i]&&d>slack[i])
d=slack[i];
for(int i=1;i<=n;i++)
if(visx[i])
lx[i]-=d;
for(int i=1;i<=n;i++)
if(visy[i])
ly[i]+=d;
else
slack[i]-=d;
int result=0;
for(int i=1;i<=n;i++)
if(match[i]>-1)
result+=g[match[i]][i];
return result;
RMQ模板
int s[50005],n,maxnum[50005][20],minnum[50005][20];
void RMQ() //预处理 O(nlogn)
int i,j;
int m=(int)(log(n*1.0)/log(2.0));
for(i=1;i<=n;i++)
maxnum[i][0]=minnum[i][0]=s[i];
for(j=1;j<=m;j++)
for(i=1;i+(1<<j)-1<=n;i++)
maxnum[i][j]=max(maxnum[i][j-1],maxnum[i+(1<<(j-1))][j-1]);
minnum[i][j]=min(minnum[i][j-1],minnum[i+(1<<(j-1))][j-1]);
int Ask_MAX (int a,int b) //O(1)
int k=int(log(b-a+1.0)/log(2.0));
return max(maxnum[a][k],maxnum[b-(1<<k)+1][k]);
int Ask_MIN (int a,int b) //O(1)
int k=int(log(b-a+1.0)/log(2.0));
return min(minnum[a][k],minnum[b-(1<<k)+1][k]);
容斥原理模板
int k,prime[N];
__int64 factor[M];
__int64 Exclusion(__in64 n)
int i,j,p=0,q;
__in64 sum=0;
factor[p++]=-1;
for(i=0;i<k;i++)
q=p;
for(j=0;j<q;j++)
factor[p++]=factor[j]*prime[i]*(-1);
for(i=1;i<p;i++)
sum+=n/factor[i];
return sum;
KMP算法模板(字符串匹配)
char s2[N],s[N*100];
int n[N];
void getnext()
int i=0,j=-1,l=strlen(s2);
n[0]=-1;
while(i<l)
if(j==-1||s2[i]==s2[j])
n[++i]=++j;
else
j=n[j];
int kmp()
getnext();
int i=0,j=0,k=0,len=strlen(s),l=strlen(s2);
while(i<len)
if(j==-1|s[i]==s2[j])
i++,j++;
else
j=n[j];
if(j==l)
k++,j=n[j];
return k;
字典树(Trie树)模板
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 15;
const int M = 26;
const int inf = 100000000;
const int mod = 2009;
struct tree
int a[M],t;
s[1000005];
char ch[N];
int p;
void init(int x)
s[x].t=0;
memset(s[x].a,-1,sizeof(s[x].a));
void buildtree()
int i,k=0;
for(i=0;ch[i]!='\\0';i++)
if(s[k].a[ch[i]-'a']==-1)
s[k].a[ch[i]-'a']=p;
init(p++);
k=s[k].a[ch[i]-'a'];
s[k].t++;
int query()
int i,k=0;
for(i=0;ch[i]!='\\0';i++)
if(s[k].a[ch[i]-'a']==-1)
return 0;
k=s[k].a[ch[i]-'a'];
return s[k].t;
int main()
int n,m,i;
while(~scanf("%d",&n))
p=0;init(p++);
for(i=0;i<n;i++)
scanf("%s",ch);
buildtree();
scanf("%d",&m);
for(i=0;i<m;i++)
scanf("%s",ch);
printf("%d\\n",query());
return 0;
Manacher算法O(n)求解回文串问题
const int N=20005;
char s[N*2];
int p[N*2],top[N*2],tail[N*2];
void Manacher()
int len = strlen(s), id = 0, maxlen = 0;
for (int i = len;i >= 0;--i)
s[i + i + 2] = s[i];
s[i + i + 1] = '#';
s[0] = '*';
for (int i = 2;i < 2 * len + 1;++i)
if (p[id] + id > i)p[i] = min(p[2 * id - i], p[id] + id - i);
else p[i] = 1;
while (s[i - p[i]] == s[i + p[i]])++p[i];
if (id + p[id] < i + p[i])id = i;
if (maxlen < p[i])maxlen = p[i];
//cout << maxlen - 1 << endl;
欧拉函数模板//计算n以内与n互质的数的个数
int euler(int n)
int ans=1,i;
for(i=2;i*i<=n;i++)
if(n%i==0)
n/=i;
ans*=i-1;
while(n%i==0)
n/=i;
ans*=i;
if(n>1)
ans*=n-1;
return ans;
最大流SAP算法(邻接矩阵)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 205;
const int M = 1005;
const int inf = 1000000007;
const int mod = 2009;
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int Map[N][N];//存图
int pre[N];//记录当前点的前驱
int level[N];//记录距离标号
int gap[N];//gap常数优化
int NV,NE;
//入口参数vs源点,vt汇点
int SAP(int vs,int vt,int n)
memset(pre,-1,sizeof(pre));
memset(level,0,sizeof(level));
memset(gap,0,sizeof(gap));
gap[0]=n;
int v,u=pre[vs]=vs,maxflow=0,aug=inf;
while(level[vs]<n)
//寻找可行弧
for(v=1;v<=n;v++)
if(Map[u][v]>0&&level[u]==level[v]+1)
break;
if(v<=n)
pre[v]=u;
u=v;
if(v==vt)
aug=inf;
//寻找当前找到的一条路径上的最大流
for(int i=v;i!=vs;i=pre[i])
if(aug>Map[pre[i]][i])
aug=Map[pre[i]][i];
maxflow+=aug;
//更新残留网络
for(int i=v;i!=vs;i=pre[i])
Map[pre[i]][i]-=aug;
Map[i][pre[i]]+=aug;
u=vs;//从源点开始继续搜
else
//找不到可行弧
int minlevel=n;
//寻找与当前点相连接的点中最小的距离标号
for(v=1;v<=n;v++)
if(Map[u][v]>0&&minlevel>level[v])
minlevel=level[v];
gap[level[u]]--;//(更新gap数组)当前标号的数目减1;
if(gap[level[u]]==0)
break;//出现断层
level[u]=minlevel+1;
gap[level[u]]++;
u=pre[u];
return maxflow;
int main()
int n,m,u,v,cap;
while(~scanf("%d%d",&n,&m))
memset(Map,0,sizeof(Map));
for(int i=1;i<=m;i++)
scanf("%d%d%d",&u,&v,&cap);
Map[u][v]+=cap;
printf("%d\\n",SAP(1,n,n));//源点为1,汇点为n,n个结点的最大流
return 0;
最大流SAP算法(邻接表)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 205;
const int M = 40005;//邻接表要开边数的2倍
const int inf = 1000000007;
const int mod = 2009;
struct Edge
int v,cap,next;
edge[2*M];
int level[N];//标记层次(距离标号)
//间隙优化,定义gap[i]为标号是i的点的个数
//在重标记i时,检查gap[level[i]],若减为0,这算法结束。
int gap[N];
int pre[N];//前驱
int cur[N];
int head[N];
int NV,NE;
//NE为边数,初始化为0;
void add_edge(int u,int v,int cap)
edge[NE].cap=cap;edge[NE].v=v;
edge[NE].next=head[u];head[u]=NE++;
edge[NE].cap=0;edge[NE].v=u;
edge[NE].next=head[v];head[v]=NE++;
//参数,源点,汇点
int SAP(int vs,int vt,int n)
bool flag;
memset(level,0,sizeof(level));
memset(pre,-1,sizeof(pre));
memset(gap,0,sizeof(gap));
//cur[i]保存的是当前弧
for(int i=0;i<=NV;i++)
cur[i]=head[i];
int u=pre[vs]=vs;//源点的pre还是其本身
int maxflow=0,aug=-1;
gap[0]=n;
while(level[vs]<NV)
flag=true;
for(int &i=cur[u];i!=-1;i=edge[i].next)
int v=edge[i].v;//v是u的后继
//寻找可行弧
if(edge[i].cap&&level[u]==level[v]+1)
//aug表示增广路的可改进量
aug==-1?(aug=edge[i].cap):(aug=min(aug,edge[i].cap));
pre[v]=u;
u=v;
//如果找到一条增广路
if(v==vt)
maxflow+=aug;//更新最大流;
//路径回溯更新残留网络
for(u=pre[v];v!=vs;v=u,u=pre[u])
//前向弧容量减少,反向弧容量增加
edge[cur[u]].cap-=aug;
edge[cur[u]^1].cap+=aug;
aug=-1;
flag=false;
break;
if(!flag)
continue;
int minlevel=n;
//寻找与当前点相连接的点中最小的距离标号(重标号)
for(int i=head[u];i!=-1;i=edge[i].next)
int v=edge[i].v;
if(edge[i].cap&&minlevel>level[v])
cur[u]=i;//保存弧
minlevel=level[v];
if((--gap[level[u]])==0)
break;//更新gap数组后如果出现断层,则直接退出。
level[u]=minlevel+1;//重标号
gap[level[u]]++;//距离标号为level[u]的点的个数+1;
u=pre[u];//转当前点的前驱节点继续寻找可行弧
return maxflow;
int main()
int m;//边的条数
while(~scanf("%d%d",&NV,&m))
memset(head,-1,sizeof(head));
NE=0;
for(int i=1;i<=m;i++)
int u,v,cap;
scanf("%d%d%d",&u,&v,&cap);
add_edge(u,v,cap);
printf("%d\\n",SAP(1,NV,NV));
return 0;
最大连续子序列和
last=ans=0;
for(i=1;i <= n;i++)
last=f_max(0,last)+b[i];
ans=f_max(ans,last);
bool searchs(int x,int len)
int left=0,right=len-1;
while(left<=right)
int mid=(left+right)/2;
if(x>s[mid])
left=mid+1;
else if(x==s[mid])
return true;
else
right=mid-1;
return false;
最长上升子序列LIS模板
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int M = 2010;
const int inf = 2147483647;
const int mod = 2009;
int a[N], f[N], d[N]; // f[i]用于记录 a[0...i]的最大长度
int bsearch(const int *f, int size, const int &a)
int l=0, r=size-1;
while( l <= r )
int mid = (l+r)>>1;
if( a > d[mid-1] && a <= d[mid] )
return mid; // >&&<= 换为: >= && <
else if( a <d[mid] )
r = mid-1;
else l = mid+1;
int LIS(const int *a, const int &n)
int i, j, size = 1;
d[0] = a[0]; f[0] = 1;
for( i=1; i < n; ++i )
if( a[i] <= d[0] ) // <= 换为: <
j = 0;
else if( a[i] > d[size-1] ) // > 换为: >=
j = size++;
else
j = bsearch(d, size, a[i]);
d[j] = a[i]; f[i] = j+1;
return size;
int main()
int t,i, n;
scanf("%d",&t);
while(t--)
memset(f,0,sizeof(f));
memset(d,0,sizeof(d));
scanf("%d",&n);
for( i=0; i < n; ++i )
scanf("%d", &a[i]);
printf("%d\\n",LIS(a, n));//求最大递增/上升子序列(如果为最大非降子序列,只需把上面的注释部分给与替换)
return 0;
强连通分量Tarjan算法模板
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 10005;
const int inf = 100000000;
const int mod = 2009;
struct edge
int to,next;
e[10*N];
int p,k,h[N],dfn[N],low[N],belong[N],ans;
bool instack[N];
stack<int> s;
void add_edge(int u,int v)
e[p].to=v;
e[p].next=h[u];
h[u]=p++;
void Clear()
ans=k=p=0;
while(!s.empty())
s.pop();
memset(h,-1,sizeof(h));
memset(instack,false,sizeof(instack));
memset(dfn,0,sizeof(dfn));
memset(belong,0,sizeof(belong));
void Tarjan(int u)//Tarjan算法求有向图的强连通分量,时间复杂度O(n+m)
int i,v,Top;
dfn[u]=low[u]=++k;
s.push(u);//入栈
instack[u]=true;//标记在栈中
for(i=h[u];i+1;i=e[i].next)
//枚举v的每一条边
v=e[i].to;//v所邻接的边
if(!dfn[v])
//未被访问
Tarjan(v);//继续向下找
low[u]=min(low[u],low[v]);//更新结点v所能到达的最小次数层
else if(instack[v])
low[u]=min(dfn[v],low[u]);
if(low[u]==dfn[u])
ans++;
while(!s.empty())
Top=s.top();
s.pop();
belong[Top]=ans;//出栈结点t属于cnt标号的强连通分量
instack[Top]=false;//标记不在栈中
if(Top==u)
break;
大数模板,涵盖各种运算(+,-,*,/,%,...),bignum的数据类型,定义变量与基本数据类型一样,例如定义一个数组,可直接bignum s[100];
不过读入需要cin
/*
+,-,*,/,% 可直接使用.
CIN读入
bignum数据类型
*/
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
#define DIGIT 4
#define DEPTH 10000
#define MAX 100//大数计算位数
typedef int bignum_t[MAX+1];
int read(bignum_t a,istream& is=cin)
char buf[MAX*DIGIT+1],ch;
int i,j;
memset((void*)a,0,sizeof(bignum_t));
if (!(is>>buf)) return 0;
for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for (i=1;i<=a[0];i++)
for (a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
for (;!a[a[0]]&&a[0]>1;a[0]--);
return 1;
void write(const bignum_t a,ostream& os=cout)
int i,j;
for (os<<a[i=a[0]],i--;i;i--)
for (j=DEPTH/10;j;j/=10)
os<<a[i]/j%10;
int comp(const bignum_t a,const bignum_t b)
int i;
if (a[0]!=b[0])
return a[0]-b[0];
for (i=a[0];i;i--)
if (a[i]!=b[i])
return a[i]-b[i];
return 0;
int comp(const bignum_t a,const int b)
int c[12]=1;
for (c[1]=b;c[c[0]]>=DEPTH;c[c[0]+1]=c[c[0]]/DEPTH,c[c[0]]%=DEPTH,c[0]++);
return comp(a,c);
int comp(const bignum_t a,const int c,const int d,const bignum_t b)
int i,t=0,O=-DEPTH*2;
if (b[0]-a[0]<d&&c)
return 1;
for (i=b[0];i>d;i--)
t=t*DEPTH+a[i-d]*c-b[i];
if (t>0) return 1;
if (t<O) return 0;
for (i=d;i;i--)
t=t*DEPTH-b[i];
if (t>0) return 1;
if (t<O) return 0;
return t>0;
void add(bignum_t a,const bignum_t b)
int i;
for (i=1;i<=b[0];i++)
if ((a[i]+=b[i])>=DEPTH)
a[i]-=DEPTH,a[i+1]++;
if (b[0]>=a[0])
a[0]=b[0];
else
for (;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);
a[0]+=(a[a[0]+1]>0);
void add(bignum_t a,const int b)
int i=1;
for (a[1]+=b;a[i]>=DEPTH&&i<a[0];a[i+1]+=a[i]/DEPTH,a[i]%=DEPTH,i++);
for (;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
void sub(bignum_t a,const bignum_t b)
int i;
for (i=1;i<=b[0];i++)
if ((a[i]-=b[i])<0)
a[i+1]--,a[i]+=DEPTH;
for (;a[i]<0;a[i]+=DEPTH,i++,a[i]--);
for (;!a[a[0]]&&a[0]>1;a[0]--);
void sub(bignum_t a,const int b)
int i=1;
for (a[1]-=b;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);
for (;!a[a[0]]&&a[0]>1;a[0]--);
void sub(bignum_t a,const bignum_t b,const int c,const int d)
int i,O=b[0]+d;
for (i=1+d;i<=O;i++)
if ((a[i]-=b[i-d]*c)<0)
a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH;
for (;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);
for (;!a[a[0]]&&a[0]>1;a[0]--);
void mul(bignum_t c,const bignum_t a,const bignum_t b)
int i,j;
memset((void*)c,0,sizeof(bignum_t));
for (c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)
for (j=1;j<=b[0];j++)
if ((c[i+j-1]+=a[i]*b[j])>=DEPTH)
c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH;
for (c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);
void mul(bignum_t a,const int b)
int i;
for (a[1]*=b,i=2;i<=a[0];i++)
a[i]*=b;
if (a[i-1]>=DEPTH)
a[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH;
for (;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
for (;!a[a[0]]&&a[0]>1;a[0]--);
void mul(bignum_t b,const bignum_t a,const int c,const int d)
int i;
memset((void*)b,0,sizeof(bignum_t));
for (b[0]=a[0]+d,i=d+1;i<=b[0];i++)
if ((b[i]+=a[i-d]*c)>=DEPTH)
b[i+1]+=b[i]/DEPTH,b[i]%=DEPTH;
for (;b[b[0]+1];b[0]++,b[b[0]+1]=b[b[0]]/DEPTH,b[b[0]]%=DEPTH);
for (;!b[b[0]]&&b[0]>1;b[0]--);
void div(bignum_t c,bignum_t a,const bignum_t b)
int h,l,m,i;
memset((void*)c,0,sizeof(bignum_t));
c[0]=(b[0]<a[0]+1)?(a[0]-b[0]+2):1;
for (i=c[0];i;sub(a,b,c[i]=m,i-1),i--)
for (h=DEPTH-1,l=0,m=(h+l+1)>>1;h>l;m=(h+l+1)>>1)
if (comp(b,m,i-1,a)) h=m-1;
else l=m;
for (;!c[c[0]]&&c[0]>1;c[0]--);
c[0]=c[0]>1?c[0]:1;
void div(bignum_t a,const int b,int& c)
int i;
for (c=0,i=a[0];i;c=c*DEPTH+a[i],a[i]=c/b,c%=b,i--);
for (;!a[a[0]]&&a[0]>1;a[0]--);
void sqrt(bignum_t b,bignum_t a)
int h,l,m,i;
memset((void*)b,0,sizeof(bignum_t));
for (i=b[0]=(a[0]+1)>>1;i;sub(a,b,m,i-1),b[i]+=m,i--)
for (h=DEPTH-1,l=0,b[i]=m=(h+l+1)>>1;h>l;b[i]=m=(h+l+1)>>1)
if (comp(b,m,i-1,a)) h=m-1;
else l=m;
for (;!b[b[0]]&&b[0]>1;b[0]--);
for (i=1;i<=b[0];b[i++]>>=1);
int length(const bignum_t a)
int t,ret;
for (ret=(a[0]-1)*DIGIT,t=a[a[0]];t;t/=10,ret++);
return ret>0?ret:1;
int digit(const bignum_t a,const int b)
int i,ret;
for (ret=a[(b-1)/DIGIT+1],i=(b-1)%DIGIT;i;ret/=10,i--);
return ret%10;
int zeronum(const bignum_t a)
int ret,t;
for (ret=0;!a[ret+1];ret++);
for (t=a[ret+1],ret*=DIGIT;!(t%10);t/=10,ret++);
return ret;
void comp(int* a,const int l,const int h,const int d)
int i,j,t;
for (i=l;i<=h;i++)
for (t=i,j=2;t>1;j++)
while (!(t%j))
a[j]+=d,t/=j;
void convert(int* a,const int h,bignum_t b)
int i,j,t=1;
memset(b,0,sizeof(bignum_t));
for (b[0]=b[1]=1,i=2;i<=h;i++)
if (a[i])
for (j=a[i];j;t*=i,j--)
if (t*i>DEPTH)
mul(b,t),t=1;
mul(b,t);
void combination(bignum_t a,int m,int n)
int* t=new int[m+1];
memset((void*)t,0,sizeof(int)*(m+1));
comp(t,n+1,m,1);
comp(t,2,m-n,-1);
convert(t,m,a);
delete []t;
void permutation(bignum_t a,int m,int n)
int i,t=1;
memset(a,0,sizeof(bignum_t));
a[0]=a[1]=1;
for (i=m-n+1;i<=m;t*=i++)
if (t*i>DEPTH)
mul(a,t),t=1;
mul(a,t);
#define SGN(x) ((x)>0?1:((x)<0?-1:0))
#define ABS(x) ((x)>0?(x):-(x))
int read(bignum_t a,int &sgn,istream& is=cin)
char str[MAX*DIGIT+2],ch,*buf;
int i,j;
memset((void*)a,0,sizeof(bignum_t));
if (!(is>>str)) return 0;
buf=str,sgn=1;
if (*buf=='-') sgn=-1,buf++;
for (a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)
ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch;
for (a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');
for (i=1;i<=a[0];i++)
for (a[i]=0,j=0;j<DIGIT;j++)
a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0';
for (;!a[a[0]]&&a[0]>1;a[0]--);
if (a[0]==1&&!a[1]) sgn=0;
return 1;
struct bignum
bignum_t num;
int sgn;
public:
inline bignum()memset(num,0,sizeof(bignum_t));num[0]=1;sgn=0;
//inline int operator!()return num[0]==1&&!num[1];
inline bignum& operator=(const bignum& a)memcpy(num,a.num,sizeof(bignum_t));sgn=a.sgn;return *this;
inline bignum& operator=(const int a)memset(num,0,sizeof(bignum_t));num[0]=1;sgn=SGN(a);add(num,sgn*a);return *this;;
inline bignum& operator+=(const bignum& a)if(sgn==a.sgn)add(num,a.num);else if(sgn&&a.sgn)int ret=comp(num,a.num);if(ret>0)sub(num,a.num);else if(ret<0)bignum_t t;
memcpy(t,num,sizeof(bignum_t));memcpy(num,a.num,sizeof(bignum_t));sub(num,t);sgn=a.sgn;else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0;else if(!sgn)memcpy(num,a.num,sizeof(bignum_t)),sgn=a.sgn;return *this;
inline bignum& operator+=(const int a)if(sgn*a>0)add(num,ABS(a));else if(sgn&&a)int ret=comp(num,ABS(a));if(ret>0)sub(num,ABS(a));else if(ret<0)bignum_t t;
memcpy(t,num,sizeof(bignum_t));memset(num,0,sizeof(bignum_t));num[0]=1;add(num,ABS(a));sgn=-sgn;sub(num,t);else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0;else if(!sgn)sgn=SGN(a),add(num,ABS(a));return *this;
inline bignum operator+(const bignum& a)bignum ret;memcpy(ret.num,num,sizeof(bignum_t));ret.sgn=sgn;ret+=a;return ret;
inline bignum operator+(const int a)bignum ret;memcpy(ret.num,num,sizeof(bignum_t));ret.sgn=sgn;ret+=a;return ret;
inline bignum& operator-=(const bignum& a)if(sgn*a.sgn<0)add(num,a.num);else if(sgn&&a.sgn)int ret=comp(num,a.num);if(ret>0)sub(num,a.num);else if(ret<0)bignum_t t;
memcpy(t,num,sizeof(bignum_t));memcpy(num,a.num,sizeof(bignum_t));sub(num,t);sgn=-sgn;else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0;else if(!sgn)add(num,a.num),sgn=-a.sgn;return *this;
inline bignum& operator-=(const int a)if(sgn*a<0)add(num,ABS(a));else if(sgn&&a)int ret=comp(num,ABS(a));if(ret>0)sub(num,ABS(a));else if(ret<0)bignum_t t;
memcpy(t,num,sizeof(bignum_t));memset(num,0,sizeof(bignum_t));num[0]=1;add(num,ABS(a));sub(num,t);sgn=-sgn;else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0;else if(!sgn)sgn=-SGN(a),add(num,ABS(a));return *this;
inline bignum operator-(const bignum& a)bignum ret;memcpy(ret.num,num,sizeof(bignum_t));ret.sgn=sgn;ret-=a;return ret;
inline bignum operator-(const int a)bignum ret;memcpy(ret.num,num,sizeof(bignum_t));ret.sgn=sgn;ret-=a;return ret;
inline bignum& operator*=(const bignum& a)bignum_t t;mul(t,num,a.num);memcpy(num,t,sizeof(bignum_t));sgn*=a.sgn;return *this;
inline bignum& operator*=(const int a)mul(num,ABS(a));sgn*=SGN(a);return *this;
inline bignum operator*(const bignum& a)bignum ret;mul(ret.num,num,a.num);ret.sg以上是关于各类模板(更新中...)(若有什么特别的需要,可以留下评论)的主要内容,如果未能解决你的问题,请参考以下文章
Linux系统有漏洞吗,若有,如何打补丁?更新升级是自动的吗,若否,命令是啥?
STM32 通过DMA收发RS485数据需要特别的电路配合吗