ACM模板[王克纯2020年9月21日最大子串int maxSum(int * a,int n){int sum = a[0],b = 0;for(int i=0;i<n;++i){if(b>0) b += a[i];else b = a[i];if(b > sum) sum = b;}return sum;}int Kadane(const int array[], size_t length, unsigned int& left, unsigned int& right){unsigned int i, cur_left, cur_right;int cur_max, max;cur_max = max = left = right = cur_left = cur_right = 0;for(i = 0; i < length; ++i){cur_max += array[i];if(cur_max > 0){cur_right = i;if(max < cur_max){max = cur_max;left = cur_left;right = cur_right;}}else{cur_max = 0;cur_left = cur_right = i + 1;}}return max;} 快速幂void js(int &a,int &b,int num) {b=1;while(num){if(num&1) b*=a;num>>=1;a*=a;}}矩阵乘法struct mat{int n,m;//n行m列int data[MAX][MAX];};void mul(const mat& a,const mat& b,mat& c) //c=a*b{int i,j,k;if (a.m!=b.n); //报错c.n=a.n,c.m=b.m;for (i=0;i<c.n;i++){for (j=0;j<c.m;j++){for (c.data[i][j]=k=0;k<a.m;k++) {c.data[i][j]+=a.data[i][k]*b.dat a[k][j]%m;//m为余数}c.data[i][j]%=m;}}}Bit位操作(宏定义,内联函数,stl)} #define bitwrite(a,i,n)(n)?(a)[(i)/8]|=1<<(i)%8:(a)[(i)/8]&=~(1<<(i)%8)//数组a的第i位写入n;#define bitread(a,i)((a)[(i)/8]>>((i)%8))&1//读取数组a的第i位inline void write(int i,int n){n?a[i/8]|=1<<i%8:a[i/8]&=~(1<<i% 8);}inline int read(int i){return (a[i/8]>>(i%8))&1;}#include<bitset>bitset<MAX> b;错排公式为M(n)=n!(1/2!-1/3!+…..+(-1)^n/n!)M(n)=n!-n!/1!+n!/2!-n!/3!+…+(-1)^n*n!/n!=sigma(k=2~n) (-1)^k*n!/k!Dn=[n!/e+0.5]容斥原理M(n)=n![1/0!-1/1!+1/2!-1/3!+1/4! +..+(-1)^n/n!]二分模板LL findr(LL array, LL low, LL high,LL target){while(low <= high){LL mid = (low + high)/2;if (array[mid] > target) high = mid - 1;else if (array[mid] < target) low = mid + 1;else return mid;}return -1;复用代码#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 10void print(mat t){printf("*****************\n") ;for(int i=0;i<t.n;i++){for(int j=0;j<t.m;j++){printf("%d",t.data[i][j]);}putchar('\n');}}一些常量和函数:最大Long long __int64 INF = ~(((__int64)0x1)<<63);ceil()向上取整(math.h)floor()向下取整c字符串处理函数1)提取子串--strstr函数原型:char* strstr(char*src,char*find)函数说明:从字符串src中寻找find第一次出现的位置(不比较结束符NULL)返回值:返回指向第一次出现find位置的指针,如果没有找到则返回NULL2)接尾连接--strcat函数原型:char* strcat(char*dest,char*src)函数说明:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'3)部分连接--strncat函数原型:char* strncat(char*dest,char*src,int n);函数说明:把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’’\0’.返回值:返回指向dest的指针。
4)将字串逆向--strrev函数原型:char*strrev(char*src)函数说明:把字符串src的所有字符的顺序颠倒过来(不包括NULL)返回值:返回指向颠倒顺序后的字符串指针C++字符串处理函数<string>string str;1. 字符串长度len = str.length();len = str.size();2. 字符串比较可以直接比较也可以:pare(str2);pare(pos1,len1,str2,pos2,len2); 值为负,0 ,正。
nops 长度到完。
3. 附加str1 += str2;或str1.append(str2);str1.append(str2.pos2,len2);4. 字符串提取str2 = str1.substr();str2 = str1.substr(pos1);str2 = str1.substr(pos1,len1);5. 字符串搜索where = str1.find(str2);where = str1.find(str2,pos1); pos1是从str1的第几位开始。
where = str1.rfind(str2); 从后往前搜。
6. 插入字符串不是赋值语句。
str1.insert(pos1,str2);str1.insert(pos1,str2,pos2,len2);str1.insert(pos1,numchar,char); numchar是插入次数,char 是要插入的字符。
7. 替换字符串str1.replace(pos1,str2);str1.replace(pos1,str2,pos2,len2);8. 删除字符串str.erase(pos,len)str.clear();9. 交换字符串swap(str1,str2);10. C --> C++char *cstr = "Hello";string str1;cstr = cstr;string str2(cstr);数学相关:PICK的定理:三角形面积s 三角形内部点n 三角形边上的点wn + w/2 - 1 = s欧几里德辗转相除法gcd(a, b) = gcd(b, a mod b)int gcd(int a, int b){int temp;while (b != 0){temp = b;b = a % b;a = temp;}return a;}PS: 最小公倍数= a * b / gcd(a, b)扩展欧几里得方程ax + by = C的(x)最小正整数解#include <stdio.h>#include <stdlib.h>int x,y,a,b;int extended_gcd(int a, int b){if (b == 0){x = 1; y = 0;return a;}else{int r = extended_gcd(b, a % b);int temp;temp = x;x = y;y = temp - a / b * y;return r;}}int main(){int i,j,m,s,c;scanf("%d%d%d", &a, &b, &c);m = extended_gcd(a,b);if (c%m!=0) {printf("error"); return 0;}x = x*(c/m);s = b/m;x = (x%s + s)%s;y = (c-x*a)/b;printf("%d %d\n", x,y);printf("gcd = %d\n", m);system("pause");}素数筛子a = 0 为素数#include <stdio.h>#include <string.h>#include <stdlib.h>#define MAX 10000int a[MAX];void odd(){int i,j;memset(a,0,sizeof(a));for (i=2;i<=MAX;i++){if (!a[i])for (j=2;j*i<=MAX;j++){a[i*j] = 1;}}}除数非互质的模线性方程//此算法可能输出0,注意细节特判,方程数为1,0时需要特判#include <stdio.h>#include <string.h>#include <stdlib.h>__int64 exgcd(__int64 a,__int64 b,__int64 &x,__int64 &y) {if(b==0){x=1,y=0;return a;}__int64 r=exgcd(b,a%b,x,y);__int64 t=x;x=y;y=t-a/b*y;return r;}int main(){__int64 flag=1,ans,x,y;//flag是否有解,ans存解得值int num;//num 方程数目scanf("%d",&num);num--;__int64 a,r;scanf("%I64d",&a);//a第一个除数scanf("%I64d",&r);//r第一个余数while(num--){__int64 b,_r;scanf("%I64d",&b);//b 除数scanf("%I64d",&_r);//_r 余数__int64 t=_r-r;__int64 d=exgcd(a,b,x,y);if(t%d) flag=0;__int64 temp=b/d;x*=t/d;x=(x%temp+temp)%temp;__int64 lcm=a*b/d;ans=a*x+r;ans=(ans%lcm+lcm)%lcm;a=lcm,r=ans;}if (flag) printf("%I64d\n",ans);else printf("No answer\n");//system("pause");}求解模线性方程组(中国余数定理)//b[0],b[1],b[2]….必须互质int ext_gcd(int a,int b,int& x,int& y){int t,ret;if (!b){x=1,y=0;return a;}ret=ext_gcd(b,a%b,x,y);t=x,x=y,y=t-a/b*y;return ret;}// x = b[0] (mod w[0])// x = b[1] (mod w[1])// ...// x = b[k-1] (mod w[k-1])//要求w[i]>0,w[i]与w[j]互质,解的范围1..n,n=w[0]*w[1]*...*w[k-1] int modular_linear_system(int b[],int w[],int k){int d,x,y,a=0,m,n=1,i;for (i=0;i<k;i++)n*=w[i];for (i=0;i<k;i++){m=n/w[i];d=ext_gcd(w[i],m,x,y);a=(a+y*m*b[i])%n;}return (a+n)%n;}生成法雷序列#include <cstdio>#include <string>#include <algorithm>using namespace std;const int MAX = 4000000;int total;int n,k;int farey[2][MAX];void make_farey_seq(int x1,int y1,int x2, int y2) {if(x1+x2 > n || y1+y2 > n) return;make_farey_seq(x1, y1,x1+x2, y1+y2);total ++;farey[0][total] = x1+x2;farey[1][total] = y1+y2;make_farey_seq(x1+x2, y1+y2,x2,y2);}int main(){int t;total = 1;farey[0][1] = 0;farey[1][1] = 1;n = 4;//n表示阶数make_farey_seq(0,1,1,1);farey[0][total+1] = 1;farey[1][total+1] = 1;while (1){scanf("%d",&t);printf("%d/%d\n",farey[0][t],farey[1][t]);}}欧拉函数int gcd(int a,int b){return b?gcd(b,a%b):a;}inline int lcm(int a,int b){return a/gcd(a,b)*b;}//求1..n-1中与n互质的数的个数int eular(int n){int ret=1,i;for (i=2;i*i<=n;i++)if (n%i==0){n/=i,ret*=i-1;while (n%i==0)n/=i,ret*=i;}if (n>1)ret*=n-1;return ret;}费马小定理•费马小定理➢设a是正整数,p是素数,且a和p互素➢则a p-1≡1 (mod p)欧拉定理➢a和n都是正整数,且a和n互素➢aΦ(n)≡1 (mod n)幂模➢a b (mod n) = a(b % Φ(n) + Φ(n)) (mod n)➢n是任意正整数,a和b是任意整数,且b不小于Φ(n) 多项式求根(牛顿法)/* 牛顿法解多项式的根输入:多项式系数c[],多项式度数n,求在[a,b]间的根输出:根要求保证[a,b]间有根*/double fabs( double x ){return (x<0)? -x : x;}double f(int m, double c[], double x){int i;double p = c[m];for (i=m; i>0; i--)p = p*x + c[i-1];return p;}int newton(double x0, double *r,double c[], double cp[], int n,double a, double b, double eps){int MAX_ITERATION = 1000;int i = 1;double x1, x2, fp, eps2 = eps/10.0;x1 = x0;while (i < MAX_ITERATION) {x2 = f(n, c, x1);fp = f(n-1, cp, x1);if ((fabs(fp)<0.000000001) && (fabs(x2)>1.0))return 0;x2 = x1 - x2/fp;if (fabs(x1-x2)<eps2) {if (x2<a || x2>b)return 0;*r = x2;return 1;}x1 = x2;i++;}return 0;}double Polynomial_Root(double c[], int n, double a, double b, double eps){double *cp;int i;double root;cp = (double *)calloc(n, sizeof(double));for (i=n-1; i>=0; i--) {cp[i] = (i+1)*c[i+1];}if (a>b) {root = a; a = b; b = root;}if ((!newton(a, &root, c, cp, n, a, b, eps)) &&(!newton(b, &root, c, cp, n, a, b, eps)))newton((a+b)*0.5, &root, c, cp, n, a, b, eps);free(cp);if (fabs(root)<eps)return fabs(root);elsereturn root;}用位运算生成所有组合情况例如生成int a[4] = {1,2,8,10}中任意取数的和的情况共2^4 = 16中情况可以这写代码:#include <stdio.h>#include <stdlib.h>#include <string.h>int main(){int i,k1,j,t;int a[4] = {1,2,8,10},ans[16];memset(ans,0,sizeof(ans));k1 = 4;t = 0;for(i=0;i<(1<<k1);i++)for(j=0;j<k1;j++)if(i&(1<<j))ans[i] += a[j];for (i=0;i<(1<<k1);i++)printf("%d ",ans[i]);system("pause");} 矩阵加速//p*q矩阵n次幂#define p 2#define q 2void multi(int a[][q],int b[][q],int c[][q])//矩阵a*b结果保存在c中{int ans[p][q] = {0};int i,j,k;for (i=0;i<p;i++){for (j=0;j<q;j++){for (k=0;k<p;k++)ans[i][j] += a[i][k]*b[k][j];}}for (i=0;i<p;i++)for (j=0;j<q;j++)c[i][j] = ans[i][j];}void ppow(int b[p][q], int n,int c[p][q]){int test;while(n>1){test = n%2;if(test==0){multi(b,b,b);n = n/2;}else{multi(c,b,c);n = n-1;}}multi(c,b,c);}调用ppow(b,n,c); b矩阵的n次幂初始化b为原矩阵c为单位矩阵结果保存在c中,每次使用都要初始化b和c矩阵加速带mod#define p 2#define q 2#define mod 10000__int64 c[2][2],n;__int64 a[2][2] = {{1,1},{1,0}};void init(__int64 c[][q]){int i,j;for (i=0;i<p;i++)for (j=0;j<q;j++)if (i==j) c[i][j] = 1;else c[i][j] = 0;}void multi(__int64 a[][q],__int64 b[][q],__int64 c[][q])//矩阵a*b结果保存在c中{__int64 ans[p][q] = {0};int i,j,k;for (i=0;i<p;i++){for (j=0;j<q;j++){for (k=0;k<p;k++){ans[i][j] += (a[i][k]*b[k][j])%mod;ans[i][j]%=mod;}ans[i][j]%=mod;if (ans[i][j]==0) ans[i][j] = mod;}}for (i=0;i<p;i++)for (j=0;j<q;j++)c[i][j] = ans[i][j];}void ppow(__int64 b[p][q], __int64 n,__int64 c[p][q]){int test;while(n>1){test = n%2;if(test==0){multi(b,b,b);n = n/2;}else{multi(c,b,c);n = n-1;}}multi(c,b,c);}//矩阵中的数》=mod 不为0故最后矩阵所有数要%mod矩阵快速幂(结构体实现)并求连续矩阵和#include<stdio.h>typedef struct node{int matrix[32][32];}Matrix;Matrix data,unit;int n,k,m;Matrix add(Matrix a,Matrix b){Matrix c;int i,j;for(i=0;i<n;i++)for(j=0;j<n;j++){c.matrix[i][j]=a.matrix[i][j]+b.matrix[i][j];c.matrix[i][j]%=m;}return c;}Matrix mul(Matrix a,Matrix b){Matrix c;int i,j,l;for(i=0;i<n;i++)for(j=0;j<n;j++){c.matrix[i][j]=0;for(l=0;l<n;l++){c.matrix[i][j]+=a.matrix[i][l]*b.matrix[l][j];c.matrix[i][j]%=m;}}return c;}Matrix power(int t){Matrix p,q;q=data;p=unit;while(t!=1){if(t&1){t--;p=mul(p,q);}else{t>>=1;q=mul(q,q);}}p=mul(p,q);return p;}Matrix mulSum(int k)//求连续n次幂和{if(k==1) return data;Matrix temp1,temp2;temp1=mulSum(k/2);if(k&1){temp2=power(k/2+1);temp1=add(temp1,mul(temp1,temp2));temp1=add(temp2,temp1);}else{temp2=power(k/2);temp1=add(temp1,mul(temp1,temp2));}return temp1;}Matrix mulSum(int k) 求奇数次幂和k为真实个数如1+3+5次和k=3{//if(k==2) return add(data,power(2));if(k==1) return data;Matrix temp1,temp2;temp1=mulSum(k/2);if(k&1){temp2=power((k/2+1)*2-1);temp1=add(temp1,mul(mul(temp1,temp2),data));temp1=add(temp2,temp1);}else{temp2=power(k);temp1=add(temp1,mul(temp1,temp2));}return temp1;}int main(){int t;Matrix r;scanf("%d %d %d",&n,&k,&m);int i,j;for(i=0;i<n;i++)for(j=0;j<n;j++){scanf("%d",&data.matrix[i][j]);unit.matrix[i][j]=(i==j);}r=mulSum(k);int sum=0;for(i=0;i<n;i++){for(j=0;j<n-1;j++)printf("%d ",r.matrix[i][j]%m);printf("%d\n",r.matrix[i][n-1]%m);}return 0;}朴素快速幂__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a;if (b%2==0){t = pow(a,b/2);return t*t;}else{return a*pow(a,b-1);}}快速幂带模__int64 mod;__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a%mod;if (b%2==0){t = pow(a,b/2)%mod;if (t==0) t = mod;t = (t*t)%mod;//if (t==0) t = mod;return t;}else{t = pow(a,b-1)%mod;//if (t==0) t = mod;t = (t*a)%mod;if (t==0) t = mod;return t;}}快速a的n次方除以b 模m__int64 mod;// a / b (mod n) = a % (b * n) / b (mod n)__int64 pow(__int64 a,__int64 b){__int64 t;if (b==0) return 1;if (b==1) return a%mod;if (b%2==0){t = pow(a,b/2)%mod;if (t==0) t = mod;t = (t*t)%mod;if (t==0) t = mod;return t;}else{t = pow(a,b-1)%mod;if (t==0) t = mod;t = (t*a)%mod;if (t==0) t = mod;return t;}}__int64 mpow(__int64 a,__int64 n,__int64 b,__int64 m)//a的n次方除以b 模m{mod = m*b;__int64 ans;ans = pow(a,n);//ans += 3;ans%=mod;ans /= b%m;}计算几何:平面欧拉公式国家数为F,边数为E,顶点数为VV+F-E=1(F≧2)立体欧拉公式V是多面体P的顶点个数,F是多面体P的面数,E是多面体P的棱的条数V+F-E=2几何公式【三角形】:1. 半周长P=(a+b+c)/22. 面积S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))3. 中线Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/24. 角平分线Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)5. 高线Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)6. 内切圆半径r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)=Ptan(A/2)tan(B/2)tan(C/2)7. 外接圆半径R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C)) 【四边形】:D1,D2为对角线,M对角线中点连线,A为对角线夹角1. a^2+b^2+c^2+d^2=D1^2+D2^2+4M^22. S=D1D2sin(A)/2(以下对圆的内接四边形)3. ac+bd=D1D24. S=sqrt((P-a)(P-b)(P-c)(P-d)),P为半周长【正n边形】:R为外接圆半径,r为内切圆半径1. 中心角A=2PI/n2. 内角C=(n-2)PI/n3. 边长a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)4. 面积S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2)) 【圆】:1. 弧长L=rA2. 弦长a=2sqrt(2hr-h^2)=2rsin(A/2)3. 弓形高h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/24. 扇形面积S1=rl/2=r^2A/25. 弓形面积S2=(rl-a(r-h))/2=r^2(A-sin(A))/2【棱柱】:1. 体积V=Ah,A为底面积,h为高2. 侧面积S=lp,l为棱长,p为直截面周长3. 全面积T=S+2A【棱锥】: 1. 体积V=Ah/3,A为底面积,h为高(以下对正棱锥)2. 侧面积S=lp/2,l为斜高,p为底面周长3. 全面积T=S+A【棱台】:1. 体积V=(A1+A2+sqrt(A1A2))h/3,A1.A2为上下底面积,h为高(以下为正棱台)2. 侧面积S=(p1+p2)L/2,p1.p2为上下底面周长,l为斜高3. 全面积T=S+A1+A2【圆柱】:1. 侧面积S=2PIrh2. 全面积T=2PIr(h+r)3. 体积V=PIr^2h【圆锥】:1. 母线L=sqrt(h^2+r^2)2. 侧面积S=PIrl3. 全面积T=PIr(L+r)4. 体积V=PIr^2h/3【圆台】:1. 母线L=sqrt(h^2+(r1-r2)^2)2. 侧面积S=PI(r1+r2)L3. 全面积T=PIr1(L+r1)+PIr2(L+r2)4. 体积V=PI(r1^2+r2^2+r1r2)h/3【球】:1. 全面积T=4PIr^22. 体积V=4PIr^3/3【球台】:1. 侧面积S=2PIrh2. 全面积T=PI(2rh+r1^2+r2^2)3. 体积V=PIh(3(r1^2+r2^2)+h^2)/6【球扇形】:1. 全面积T=PIr(2h+r0),h为球冠高,r0为球冠底面半径2. 体积V=2PIr^2h/3确定连续线段是向左转还是向右转struct point{double x, y;};//计算p3相对于p1p2的转向(p1p3 相对于p1p2)//返回>0 逆时针,<0顺时针(p1p3相对于p1p2)double direction(point p1, point p2, point p3){return (p3.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p3.y - p1.y);}判断线段相交,共端点也算bool online(node p1, node p2, node p3){return (p3.x >= min(p1.x, p2.x) && p3.x <= max(p1.x, p2.x)&& p3.y >= min(p1.y,p2.y) && p3.y <= max(p1.y, p2.y));}bool insect(node p1, node p2, node p3, node p4){double d1 = direction(p3, p4, p1);double d2 = direction(p3, p4, p2);double d3 = direction(p1, p2, p3);double d4 = direction(p1, p2, p4);if (d1 * d2 < 0 && d3 * d4 < 0) return true;else if (d1 == 0 && online(p3, p4, p1)) return true;//共点的情况else if (d2 == 0 && online(p3, p4, p2)) return true;else if (d3 == 0 && online(p1, p2, p3)) return true;else if (d4 == 0 && online(p1, p2, p4)) return true;return false;}判断线段和直线相交(p1,p2是线段的两个端点,p3,p4为直线上不相同的两点)bool insect(node p1, node p2, node p3, node p4){double d1 = direction(p3, p4, p1);double d2 = direction(p3, p4, p2);return (d1 * d2 < 0 || d1 == 0 || d2 == 0);}Graham扫描法求凸包#include <stdio.h>#include <algorithm>using namespace std;int max(int a,int b){return a>b?a:b;}int min(int a,int b){return a>b?b:a;}struct node{int x;int y;};struct node x[10010];int ans[10010], cnt,n;//cnt记录凸包元素个数,实际个数bool cmp(node p1, node p2){int temp = (p1.x - x[0].x) * (p2.y - x[0].y) - (p2.x - x[0].x) * (p1.y - x[0].y);if (temp == 0) return (p1.x >= min(x[0].x, p2.x) && p1.x <= max(x[0].x, p2.x));else return temp > 0;}bool CrossLeft(node p1, node p2, node p3)//p3是否严格左转,共线不算左转这样是点最少的凸包,共线点只算一个{return ((p3.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p3.y - p1.y)) < 0;}void Graham(){sort(x + 1, x + n, cmp);cnt = 0; // 以第一个点为基准,逆时针排序ans[cnt++] = 0;ans[cnt++] = 1;for(int i = 2; i < n; i++){while(cnt > 1 && !CrossLeft(x[ans[cnt - 2]], x[ans[cnt - 1]], x[i])) cnt--;ans[cnt++] = i;}ans[cnt++] = 0;cnt--;}读入的时候从0开始读点,最小点(优先y最小,其次x最小)交换到x[0]处点的标号保存在ans里,共cnt个,从0——cnt-1Ans的标号是排过序以后的不与输入的编号对应叉积判断直线相交情况,求交点这里也用到叉积的原理。