目录
大数输入输出及定义:__int128 b=p-1; prin(b); scan(t);
输入汇总
实现空格输入
//c语言
int i=0;
while(scanf("%c",&s[i])!=EOF){//多组输入
if(s[i]!='\n') ++i;
else {
int len=i;
i=0;
}
}
int i=0;
while(scanf("%c",&s[i])&&s[i]!='\n'){//单组输入
++i;
}
int len=i;
i=0;
printf("%s\n",s);
//c++实现string
string t;
getline(cin,t);
cout<<t<<endl;
//c++实现char 数组
char s[N]
cin.getline(s,N);
puts(s);
printf("%d\n",strlen(s));
文件读取
freopen("A.txt","w",stdout);
fclose(stdout);
freopen("A.txt","r",stdin);
fclose(stdin);
GCD+LCM+矩阵快速幂+素数大表
GCD 最大公约数 (logn)
gcd(a,0) = a;
gcd (a,b) = gcd(b,a%b)
//gcd
//gcd(a,0)=a;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
LCM最小公倍数
lcm (a,b) =
素数
素数打表
比埃拉托斯特尼筛法
基本思想:素数的倍数一定不是素数
//素数打表
prim[1]=1;
for(int i=2;i*i<TOP;++i)
if(!prim[i])
for(int j=i*i;j<TOP;j+=i)
prim[j]=1;
素数判断:6倍法
bool check(long long n){
if(n<=3) return n>1;
if(n%6!=1&&n%6!=5) return false;
int t=sqrt(n);
for(long long i=5;i<=t;i+=6){
if(n%i==0||n%(i+2)==0) return false;
}
return true;
}
素数判断普通法
bool check isPrime(int n) {
if (n <= 3) {
return n > 1;
}
int sqrt = (int)sqrt(n);
for (int i = 2; i <= sqrt; i++) {
if(n % i == 0) {
return false;
}
}
return true;
}
快速幂
typedef long long LL
//快速幂
LL pow_mod(LL a,LL n){
LL res=1;
while(n){
if(n&1) res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
二分
int l=1,r=n;
while (l <=r){
int mid =(l+r )/2;
if(a[mid ]== x){
return mid ;
} else if(a[mid]>x){
r=mid -1;
} else {
l=mid +1;
}
}
return -1;
upper_bound lower_bound
vector+set+map+string
vector
vector <int >ve;
vector <node > ve;
vector <char > ve;
vector <int > V[ MAXN ]
ve. clear () 移除容器中所有数据。
ve. push_back (i) 存入数据i.
ve. seiz () 返回数组的大小。
ve. begin () 返回迭代器的第一个数据。
ve.end () 返回迭代器的最后一个数据。
set (logn)
set <int >se;
set <char > se;
set <int >S[ MAXN ]
se. begin () 返回指向第一个元素的迭代器
se. clear () 清除所有元素
se. count () 返回某个值元素的个数
se. empty () 如果集合为空,返回true
se.end () 返回指向最后一个元素之后的迭代器,不是最后一个元素
se. erase () 删除集合中的元素
se. find () 返回一个指向被查找到元素的迭代器
se. insert () 在集合中插入元素
se. max_size () 返回集合能容纳的元素的最大限值
se. size () 集合中元素的数目
se. swap () 交换两个集合变量
跌代器
for(set <int >:: iterator z = se. begin (); z != se.end ();
{ }
map(logn)
map<int,int>mp;
map<int,int>::iterator it;
for(it= mp.begin();it!=mp.end();++it)
it->first;
it->second;
----------
map<string,map<string,int> > mp;
mp[ss][s]+=x;
map<string,map<string,int> >::iterator it;
map<string,int>::iterator is;
for(it=mp.begin();it!=mp.end();++it){
cout<<it->first<<endl;
for(is= it->second.begin();is!=it->second.end();++is){
cout<<is->first<<"("<<is->second<<")"<<endl;
}
}
string
队列栈
栈
//代码实现(以int为例)
stack <int > sta ;
sta . push ();
sta . pop ();
sta . top ();
sta . empty ();
//栈和队列的清空
while (! sta . empty ()) sta . pop ();
普通队列
queue <int > que ;
que . push ();
//元素出栈(队列)
que . pop ();
//查询栈顶元素 查询队列顶端元素
que . front ();
//判断栈(队列)是否为空
que . empty ();
//栈和队列的清空
while (! que . empty ()) que . pop ();
优先队列
//代码实现
priority_queue <int > que ;
que . push ();
que . pop ();
que . top ();
que . empty ();
//优先级的设置
//结构体(和cmp类似)
struct node
{
int x,y;
friend bool operator<(node a , node b)//排序放在里面要写friend;
{
if(a.x == b.x) return a.y>b.y;//Y从大到小 //排序与题意要相反
return a.x<b.x;//X从小到大;
}
};
priority_queue < node > que ;
----------------------------------------------
priority_queue <int , vector <int > , greater <int > > que ;// 小到大
priority_queue <int , vector <int > , less <int > > que ;
sort+结构体
//定义结构体
struct student {
char name [20];
int score ;
int age ;
int id ;
} s1 , s2 ;
--------------------------------------
struct node {
int x , y ; char c [100];
node & operator = ( const node & b ){
y = b .y , x = b . x ;
strcpy (c , b . c );
return * this ; }
} a ;
node b ; b = a ;
------------------------------------
bool cmp ( node a , node b ){
if ( a . x == b . x ){
if ( a . y == b . y )
return strcmp ( a .c , b . c ) <0;//字典序升序
else return a . y < b . y ;//y升序
}
return a . x < b . x ;//x升序
}
bool cmp (int a ,int b ){
return a > b ;//降序
}
sort (a , a +n , cmp );
同余定理+逆元
逆元
费马小定理
/*
费马小定理:p是质数且gcd(a,p)==1
-> a^(p-1)%p=1
->a的逆元为 a^(p-2)
*/
long long quickpow(long long a,long long b){
if(b<0) return 0;
long long res=1;
a%=mod;
while(b){
if(b&1) res=(res*a)%mod;
a=(a*a)%mod;
b>=1;
}
return res;
}
long long inv(long long a){
return quickpow(a,mod-2);
}
扩展欧几里得求逆元
/*
a*x%mod==1 ->a*x+m*y==1
(x+mod)%mod 即为a的逆元
*/
long long exgcd(long long a,long long b,long long &x,long long &y){
if(!b){
x=1;
y=0;
return a;
}
else{
long long r=exgcd(b,a%b,y,x);
y-=x*(a/b);
return r;
}
}
long long inv(long long a){
long long x,y;
long long d=exgcd(a,mod,x,y);
return x=(x+mod)%mod;
}
递推求逆元(打表)
long long inv[N];
void prepare_inv(int n,int M){
inv[1]=1;
for(int i=2;i<=n;++i){
inv[i]=(long long)(M-M/i)*inv[M%i]%M;
}
}
大数取模
int len = a. length ();
int ans = 0;
for (int i = 0; i < len; i ++){
ans = (ans * 10 + a[i] - ’0’) mod b;
}
大数输入输出及定义:__int128 b=p-1; prin(b); scan(t);
void scan(__int128 &x)
{
int f = 1;
char ch;
x = 0;
if (ch = getchar() == '-') f = -1;
else x += ch - '0';
while ((ch == getchar()) >= '0' && ch <= '9')
x = x * 10 + ch - '0';
x *= f;
}
void print(__int128 x)
{
if (!x) return ;
if (x < 0) putchar('-'),x = -x;
print(x / 10);
putchar(x % 10 + '0');
}
__int128 vi(__int128 a,__int128 b){
__int128 mod=b+2;
__int128 res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
背包
//01
int dp[MAXN];
for(int i=0;i<n;i++)
for(int j=W;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);
//完全
int dp[MAXN];
for(int i=0;i<n;i++)
for(int j=w[i];j<=W;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);
//多重背包
for(int i=0;i<n;i++){
int num=m[i];// 用来找a
for(int k=1;num >0;k< <=1){
int mul=min(k,num);
for(int j=W;j>=w[i]*mul;j--){
dp[j]=max(dp[j],dp[j-w[i]*mul]+v[i]*mul);
}
num -=mul;
}
}
printf("%d\n",dp[W]);
//分组背包
这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。
也就是说设F[k; v] 表示前k 组物品花费费用v 能取得的最大权值,则有:
F[k; v] = maxfF[k ? 1; v]; F[k ? 1; v ? Ci] +Wi j item i 2 group kg
使用一维数组的伪代码如下:
for k 1 to K
for v V to 0
for all item i in group k
F[v] maxfF[v]; F[v ? Ci] +Wig
这里三层循环的顺序保证了每一组内的物品最多只有一个会被添加到背包中。
并查集
int find (int x)
{
int r=x;
while (pre[r ]!=r)
r=pre[r ] ;
return r ;
}
//路径压缩
int find (int x){
int r=x;
while ( pre[r ] != r )
r=pre[r ];
int i=x , j ;
while ( i != r ){
j = pre[ i ];
pre [ i ]= r ;
i=j;
}
return r ;
}
拓扑排序
queue<int>que;
int inDegree[200000];
int count = 0;
int len = prerequisites.size();
int u,v;
memset(inDegree,0,sizeof(int)*numCourses);
for(int i=0;i<len ; ++ i){
// u= prerequisites[i][1];
v = prerequisites[i][0];
inDegree[v]++;//统计入度
}
for(int i=0;i<numCourses; ++i){
if(inDegree[i]==0){
que.push(i);//入度为0放在队列
}
}
while(!que.empty()){
u = que.front();//入度为0的节点U
que.pop();
count++;//用于计算最后有没有环
for(int i=0;i<len;++i){
if(prerequisites[i][1]==u){
v=prerequisites[i][0];//存在u->v的边,v的入度--
inDegree[v]--;
if(inDegree[v]==0){
que.push(v);
}
}
}
}
if(count<numCourses) return false;//有环
return true;
KMP
//n=strlen(s);
//m=strlen(t);
void getnex(){///nex[]数组获取
int i=1,j=0;
nex[0]=0;
while(i<n){
if(t[i]==t[j])
nex[i++]=++j;
else if(!j)
++i;
else
j=nex[j-1];
}
}
int kmp(){//KMP函数
int i=0,j=0,ans=0;
nex[0]=0;
while(i<n){
if(s[i]==t[j]){
++i;
++j;
}
else if(!j)
++i;
else
j=nex[j-1];
if(j==m){
ans++;//记录循环次数
j=nex[j-1];//nex[]数组失配总是要返回最近的循环节,若返回j=0会超时
}
}
return ans;
}
if(!nex[n-1]) //若nex[n-1] 为0,则说明没有循环,需要补充跟原串一样长度
printf("%d\n",n);
else if(n%(n-nex[n-1])==0&&nex[n-1]!=0)//nex[n-1]回溯到最近的循环节,即跟【循环节后面不再循环的多余的串】一样的 最近位置
printf("%d\n",0) ; //n-nex[n-1]即为循环的串的长度,n/(n-nex[n-1]为循环几次,
else
printf("%d\n",n-nex[n-1]-n%(n-nex[n-1]));//循环串长度-总长%循环串长度
最短路
const int M=3000;
const int N=508;
const int inf=100000008;
int head[N],d[N],top,vis[N],num[M<<1];
int dis[N];
struct Edge{
int to,val,next;
Edge(){}
Edge(int _to,int _val,int _next){
to=_to;
val=_val;
next=_next;
}
}edge[M<<1];
void inif(int n){
for(int i=0;i<=n;++i) dis[i]=inf;
memset(head,-1,sizeof(int)*(n+1));
top=0;
memset(vis,0,sizeof(int)*(n+1));
memset(num,0,sizeof(num));
}
void add(int u,int v,int w){//建图
edge[top]=Edge(v,w,head[u]);
head[u]=top++;
}
int spfa(int st,int ed){
dis[st]=0;
queue<int>que;
while(!que.empty() ) que.pop();
que.push(st);
num[st]++;
vis[st]=1;
bool fg=false;
while(!que.empty() ){
int u=que.front() ;
que.pop() ;
vis[u]=0;
for(int i=head[u];~i;i=edge[i].next ){
Edge e=edge[i];
if(dis[e.to ]>dis[u]+e.val ){
dis[e.to ]=dis[u]+e.val ;
if(!vis[e.to ]){
vis[e.to ]=1;
que.push(e.to );
num[e.to ]++;//记录节点跑的次数
if(num[e.to ]>n){
return 1;
}
}
}
}
}
return 0;
}
矩阵快速幂
矩阵快速幂
int f=2;
long long n,mod=1024;
struct node{
LL materix[3][3];
};
node mul(node a,node b){
node res;
memset(res.materix,0,sizeof(res.materix));
for(int i=1;i<=f;++i){
for(int j=1;j<=f;++j){
for(int k=1;k<=f;++k){
res.materix[i][j]=(res.materix[i][j]+a.materix[i][k]*b.materix[k][j])%mod;
}
}
}
return res;
}
node ksm(node a,long long b){
node ans;
memset(ans.materix,0,sizeof(ans.materix));
for(int i=1;i<=f;++i) ans.materix[i][i]=1;
while(b){
if(b&1LL) ans=mul(ans,a);
a=mul(a,a);
b>>=1LL;
}
return ans;
}
重载版
struct node{
LL materix[7][7];
void init(){
memset(materix ,0,sizeof(materix ));
}
void init1(){
memset(materix,0,sizeof(materix));
for(int i=1;i<=ff;++i ) materix[i][i]=1;
}
node operator *(const node B) const{
node C;
C.init();
for(int i=1;i<=ff;++i){
for(int j=1;j<=ff;++j){
for(int k=1;k<=ff;++k){
C.materix[i][j]=(materix[i][k]*B.materix[k][j]+C.materix[i][j])%mod;
}
}
}
return C;
}
node ksm(node a,long long b){
node ans;
ans.init1() ;
while(b){
if(b&1LL) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
快读
//快读(数字)
int read()
{
int ans = 0;
char c;
c = getchar();
while (c >= '0' && c <= '9') ans= ans * 10 + c-'0',c=getchar();
return ans;
}
LCA
//倍增法
int n,m,root,h;//n个点,m次查询,root根节点,h最多跳h次
const int N=1000000,D=30;
int parent[D][N],depth[N];
int head[N],top;
struct Edge{
int v,nex;
Edge(){ };
Edge(int _v,int _nex){
v=_v;
nex=_nex;
}
}edge[N];
void add(int u,int v){
edge[top]=Edge(v,head[u]);
head[u]=top++;
}
void dfs(int v,int p,int d){
parent[0][v]=p;
depth[v]=d;
for(int i=head[v] ;~i;i=edge[i].nex ){
if(edge[i].v !=p)
dfs(edge[i].v ,v,d+1);
}
}
void init(int V){
dfs(root,-1,0);
for(int k=0;k+1<h;++k){
for(int v=1;v<=V;++v){
if(parent[k][v]<0)
parent[k+1][v]=-1;
else
parent[k+1][v]=parent[k][parent[k][v]];
}
}
}
int lca(int u,int v){
if(depth[u]>depth[v]) swap(u,v);
for(int k=0;k<h;++k){
if((depth[v]-depth[u])>>k&1){
v=parent[k][v];
}
}
if(u==v) return u;
for(int k=h-1;k>=0;--k){
if(parent[k][u]!=parent[k][v]){
u=parent[k][u];
v=parent[k][v];
}
}
return parent[0][u];
}
int main(){
int u,v;
while(~scanf("%d%d%d",&n,&m,&root)){
memset(head,-1,sizeof(int)*(n+1));
top=0;
for(int i=1;i<n;++i){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
h=(int)log2(n);
init(n);
for(int i=0;i<m;++i){
scanf("%d%d",&u,&v);
printf("%d\n",lca(u,v));
}
}
return 0;
}
//tarjan求LCA
#include<cstdio>
#define N 1000050
struct hehe{
int next;
int to;
int lca;
};
hehe edge[N];//树的链表
hehe qedge[N];//需要查询LCA的两节点的链表
int n,m,p,x,y;
int num_edge,num_qedge,head[N],qhead[N];
int father[N];
int visit[N];//判断是否被找过
void add_edge(int from,int to){//建立树的链表
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void add_qedge(int from,int to){//建立需要查询LCA的两节点的链表
qedge[++num_qedge].next=qhead[from];
qedge[num_qedge].to=to;
qhead[from]=num_qedge;
}
int find(int z){//找爹函数
if(father[z]!=z)
father[z]=find(father[z]);
return father[z];
}
void dfs(int x){//把整棵树的一部分看作以节点x为根节点的小树
father[x]=x;//由于节点x被看作是根节点,所以把x的father设为它自己
visit[x]=1;//标记为已被搜索过
for(int k=head[x];k;k=edge[k].next)//遍历所有与x相连的节点
if(!visit[edge[k].to]){//若未被搜索
dfs(edge[k].to);//以该节点为根节点搞小树
father[edge[k].to]=x;//把x的孩子节点的father重新设为x
}
for(int k=qhead[x];k;k=qedge[k].next)//搜索包含节点x的所有询问
if(visit[qedge[k].to]){//如果另一节点已被搜索过
qedge[k].lca=find(qedge[k].to);//把另一节点的祖先设为这两个节点的最近公共祖先
if(k%2)//由于将每一组查询变为两组,所以2n-1和2n的结果是一样的
qedge[k+1].lca=qedge[k].lca;
else
qedge[k-1].lca=qedge[k].lca;
}
}
int main(){
scanf("%d%d%d",&n,&m,&p);//输入节点数,查询数和根节点
for(int i=1;i<n;++i){
scanf("%d%d",&x,&y);//输入每条边
add_edge(x,y);
add_edge(y,x);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);//输入每次查询,考虑(u,v)时若查找到u但v未被查找,所以将(u,v)(v,u)全部记录
add_qedge(x,y);
add_qedge(y,x);
}
dfs(p);//进入以p为根节点的树的深搜
for(int i=1;i<=m;i++)
printf("%d\n",qedge[i*2].lca);//两者结果一样,只输出一组即可
return 0;
}
tarjan算法
//tarjan
#define N 30100
//N为最大点数
#define M 150100
//M为最大边数
int n, m;//n m 为点数和边数
struct Edge{
int from, to, nex;
bool sign;//是否为桥
}edge[M<<1];
int head[N], edgenum;
void add(int u, int v){//边的起点和终点
Edge E={u, v, head[u], false};
edge[edgenum] = E;
head[u] = edgenum++;
}
int DFN[N], Low[N], Stack[N], top, Time;
//Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)
int taj;//连通分支标号,从1开始
int Belong[N];//Belong[i] 表示i点属于的连通分支
bool Instack[N];
vector<int> bcc[N]; //标号从1开始
void tarjan(int u ,int fa){
DFN[u] = Low[u] = ++ Time ;
Stack[top ++ ] = u ;
Instack[u] = 1 ;
for (int i = head[u] ; ~i ; i = edge[i].nex ){
int v = edge[i].to ;
if(DFN[v] == -1)
{
tarjan(v , u) ;
Low[u] = min(Low[u] ,Low[v]) ;
if(DFN[u] < Low[v])
{
edge[i].sign = 1;//为割桥
}
}
else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;
}
if(Low[u] == DFN[u]){
int now;
taj ++ ; bcc[taj].clear();
do{
now = Stack[-- top] ;
Instack[now] = 0 ;
Belong [now] = taj ;
bcc[taj].push_back(now);
}while(now != u) ;
}
}
void tarjan_init(int all){
memset(DFN, -1, sizeof(DFN));
memset(Instack, 0, sizeof(Instack));
top = Time = taj = 0;
for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!
}
vector<int>G[N];
int du[N];
void suodian(){
memset(du, 0, sizeof(du));
for(int i = 1; i <= taj; i++)G[i].clear();
for(int i = 0; i < edgenum; i++){
int u = Belong[edge[i].from], v = Belong[edge[i].to];
if(u!=v) G[u].push_back(v), du[v]++;
}
}
void init(){memset(head, -1, sizeof(head)); edgenum=0;}