博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOIp知识集合 By cellur925
阅读量:4963 次
发布时间:2019-06-12

本文共 17087 字,大约阅读时间需要 56 分钟。

基本算法

  • 快速幂
1 ll ksm(ll a,ll b) 2 { 3     ll ans=1; 4     while(b) 5     { 6         if(b&1) ans=ans*a%p; 7         b>>=1; 8         a=a*a%p; 9     }10     return ans;11 }
ksm
  • 64位大整数乘法
1 ll mul(ll a,ll b) 2 { 3     ll ans=0; 4     while(b) 5     { 6         if(b&1) ans=(ans+a)%p; 7         b>>=1; 8         a=a*2%p; 9     }10     return ans;11 }
mul
  • 离散化
1     for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];2     sort(b+1,b+1+n);3     int cnt=unique(b+1,b+1+n)-(b+1);4     for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
discrete
  • 归并排序求逆序对
1 void mergesort(int l,int r) 2 { 3     if(l==r) return ; 4     int mid=(l+r)>>1; 5     mergesort(l,mid); 6     mergesort(mid+1,r); 7     int i=l,j=mid+1,k=l-1; 8     while(i<=mid&&j<=r) 9     {10         if(a[i]<=a[j]) b[++k]=a[i],i++;11         else b[++k]=a[j],j++,(ans+=mid-i+1)%=moder;12     }13     while(i<=mid) b[++k]=a[i],i++;14     while(j<=r) b[++k]=a[j],j++;15     for(int qwq=l;qwq<=r;qwq++) a[qwq]=b[qwq];16 }
mergesort
  • 全排列
1 void dfs(int x) 2 { 3     for(int i=1;i<=n;i++) 4         if(!vis[i]) 5         { 6             seq[x]=i; 7             vis[i]=1; 8             if(x==n) work(); 9             else dfs(x+1);10             vis[i]=0;11         }12 }
Permutation
  • ST表
1 #include
2 #include
3 #include
4 5 using namespace std; 6 7 int n,m; 8 int st[100090][30]; 9 10 int sta(int l,int r)11 {12 int k=log2(r-l+1);13 return max(st[l][k],st[r-(1<
ST Table
  • 两种二分
1 while(l
>1; 4 if(check(mid)) r=mid; 5 else l=mid+1; 6 } 7 while(l
>1;10 if(check(mid)) r=mid-1;11 else l=mid;12 }
整数域二分
1 double eps=1e-8;2 while(l+eps
实数域二分
  • 康拓展开及其求逆 
1 void Recantor(ll x) 2 { 3     memset(vis,0,sizeof(vis)); 4     x--; 5     int j=0; 6     for(int i=1;i<=n;i++) 7     { 8         ll t=x/fac[n-i]; 9         for(j=1;j<=n;j++)10             if(!vis[j])11             {12                 if(!t) break;13                 t--;14             }15         printf("%d ",j);16         vis[j]=1;17         x%=fac[n-i]; 18     }19     printf("\n");20 }21 22 ll cantor()23 {24     ll ans=1;25     for(int i=1;i<=n;i++)26     {27         int tot=0;28         for(int j=i+1;j<=n;j++)29             if(a[j]
Cantor&Recantor

其他算法

  • 莫队算法(不带修)
1 bool cmp(query a,query b) 2 { 3     return (a.l/block)^(b.l/block) ? a.l
b.r); 4 }//奇偶块排序 5 6 7 8 block=sqrt(n); 9 for(int i=1;i<=n;i++) scanf("%d",&seq[i]);10 for(int i=1;i<=m;i++)11 {12 scanf("%d%d",&ask[i].l,&ask[i].r);13 ask[i].id=i;14 ask[i].in=ask[i].l/block;15 }16 sort(ask+1,ask+1+m,cmp);17 for(int i=1;i<=m;i++)18 {19 int l=ask[i].l,r=ask[i].r;20 while(posl
r) remove(posr--);22 while(posl>l) add(--posl);23 while(posr
Mo's Algorithm

数学

  • 预处理阶乘和处理逆元求组合数
1 ll exgcd(ll a,ll b,ll &x,ll &y) 2 { 3     if(b==0)   4     {   5           x=1;   6           y=0;   7           return a;   8     }   9     int gu=exgcd(b,a%b,x,y);  10     int t=x;  11     x=y;  12     y=t-a/b*y;  13     return gu;  14 15 }16 17 ll niyuan(ll hu)18 {19     x=0,y=0;20     ll tmp=exgcd(hu,p,x,y);21     return (x+p)%p;22 }23 24 ll C(ll k,ll m)25 {26     ll up=fac[k]%p;27     ll down=fac[m]%p*fac[k-m]%p;28     ll ans=up*niyuan(down)%p;29     return ans;30 }31 32 void pre()33 {34     fac[0]=1;35     for(int i=1;i<=n+1;i++)36         fac[i]=(ll)fac[i-1]*i%p;37 }
Combination
  • 杨辉三角求组合数

1     C[0][0]=1;C[1][1]=1;2     for(int i=1;i<=n;i++) C[i][0]=1,C[i][i]=1;3     for(int i=1;i<=n;i++)4         for(int j=1;j<=i;j++)5             (C[i][j]=C[i-1][j]+C[i-1][j-1])%=moder;
Yang's triangle

 

数据结构

  • $vector$实现普通平衡树 慎用!!!
1 #include
2 #include
3 #include
4 5 using namespace std; 6 7 int n; 8 vector
v; 9 10 int main()11 {12 scanf("%d",&n);13 for(int i=1;i<=n;i++)14 {15 int op=0,x=0;16 scanf("%d%d",&op,&x);17 if(op==1) v.insert(upper_bound(v.begin(),v.end(),x),x);18 else if(op==2) v.erase(lower_bound(v.begin(),v.end(),x));19 else if(op==3) printf("%d\n",lower_bound(v.begin(),v.end(),x)-v.begin()+1);20 else if(op==4) printf("%d\n",v[x-1]);21 else if(op==5) printf("%d\n",*--lower_bound(v.begin(),v.end(),x));22 else if(op==6) printf("%d\n",*upper_bound(v.begin(),v.end(),x));23 }24 return 0;25 }26 /*27 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:28 1. 插入x数29 2. 删除x数(若有多个相同的数,因只删除一个)30 3. 查询x数的排名(若有多个相同的数,因输出最小的排名)31 4. 查询排名为x的数32 5. 求x的前驱(前驱定义为小于x,且最大的数)33 6. 求x的后继(后继定义为大于x,且最小的数)34 */
Balanced Tree By vector

图论

  • Floyd算法。复杂度$O(n^3)$
1     memset(dis,0x3f,sizeof(dis)); 2     for(int i=1;i<=v;i++) dis[i][i]=0,dis[0][i]=0;//这一步很重要 3     for(int i=1;i<=e;i++) 4     { 5         int x=0,y=0,z=0; 6         scanf("%d%d%d",&x,&y,&z); 7         dis[x][y]=min(dis[x][y],z); 8         dis[y][x]=min(dis[y][x],z); 9     }10     for(int kk=1;kk<=v;kk++)11         for(int i=1;i<=v;i++)12             for(int j=1;j<=v;j++)13                 dis[i][j]=min(dis[i][j],dis[i][kk]+dis[kk][j]);
floyd
  • Dijkstra+堆优化。复杂度$O(mlogn)$。稠密图优。好像不能用来跑最长路诶(
1 void dijkstra() 2 { 3     priority_queue
>q; 4 memset(dis,0x3f,sizeof(dis)); 5 dis[s]=0;q.push(make_pair(0,s)); 6 while(!q.empty()) 7 { 8 int u=q.top().second;q.pop(); 9 if(vis[u]) continue;10 vis[u]=1;11 for(int i=head[u];i;i=edge[i].next)12 {13 int v=edge[i].to;14 if(dis[v]>dis[u]+edge[i].val)15 {16 dis[v]=dis[u]+edge[i].val;17 q.push(make_pair(-dis[v],v));18 }19 }20 }21 }
Dijkstra+Heap
  • spfa过世算法复杂度理解为$O(nm)$。但稀疏图$O(km)$。
1 void spfa() 2 { 3     memset(dis,0x3f,sizeof(dis)); 4     queue
q; 5 q.push(s),vis[s]=1,dis[s]=0; 6 while(!q.empty()) 7 { 8 int u=q.front();q.pop(); 9 vis[u]=0;10 for(int i=head[u];i;i=edge[i].next)11 {12 int v=edge[i].to;13 if(dis[v]>dis[u]+edge[i].val)14 {15 dis[v]=dis[u]+edge[i].val;16 if(!vis[v]) q.push(v),vis[v]=1;17 }18 }19 }20 }
spfa
  • 判断树上两路径是否相交

*  题目:LuoguP3398仓鼠找sugar / 计蒜客NOIP提高组模拟一试T2 敌对势力 / hihocoder 11D(题目找不到了==可以看这位dalao的)

1 #include
2 #include
3 #include
4 #include
5 #define maxn 100090 6 7 using namespace std; 8 9 int n,m,tot,t; 10 int head[maxn],d[maxn],f[maxn][20]; 11 struct node{ 12 int to,next; 13 }edge[maxn*2]; 14 15 void add(int x,int y) 16 { 17 edge[++tot].to=y; 18 edge[tot].next=head[x]; 19 head[x]=tot; 20 } 21 22 void LCA_prework() 23 { 24 queue
q; 25 q.push(1);d[1]=1; 26 while(!q.empty()) 27 { 28 int u=q.front();q.pop(); 29 for(int i=head[u];i;i=edge[i].next) 30 { 31 int v=edge[i].to; 32 if(d[v]) continue; 33 d[v]=d[u]+1; 34 f[v][0]=u; 35 for(int j=1;j<=t;j++) 36 f[v][j]=f[f[v][j-1]][j-1]; 37 q.push(v); 38 } 39 } 40 } 41 42 int LCA(int x,int y) 43 { 44 if(d[x]>d[y]) swap(x,y); 45 for(int i=t;i>=0;i--) 46 if(d[f[y][i]]>=d[x]) y=f[y][i]; 47 if(x==y) return x; 48 for(int i=t;i>=0;i--) 49 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 50 return f[x][0]; 51 } 52 53 int main() 54 { 55 scanf("%d%d",&n,&m); 56 t=log2(n)+1; 57 for(int i=1;i<=n-1;i++) 58 { 59 int x=0,y=0; 60 scanf("%d%d",&x,&y); 61 add(x,y);add(y,x); 62 } 63 LCA_prework(); 64 for(int i=1;i<=m;i++) 65 { 66 int a=0,b=0,c=0,e=0; 67 scanf("%d%d%d%d",&a,&b,&c,&e); 68 int Chemist=LCA(a,b); 69 int cellur=LCA(c,e); 70 if(Chemist==cellur) 71 { 72 printf("NO\n"); 73 continue; 74 } 75 if(d[Chemist]>d[cellur]) 76 { 77 if(LCA(Chemist,c)==Chemist||LCA(Chemist,e)==Chemist) 78 { 79 printf("NO\n"); 80 continue; 81 } 82 else 83 {
//没有相交输出yes 84 printf("YES\n"); 85 continue; 86 } 87 } 88 else 89 { 90 if(LCA(cellur,a)==cellur||LCA(cellur,b)==cellur) 91 { 92 printf("NO\n"); 93 continue; 94 } 95 else 96 { 97 printf("YES\n"); 98 continue; 99 }100 }101 }102 103 return 0;104 }
View Code
  • 最短路计数
#include
#include
#include
#include
using namespace std;typedef long long ll;int n,m,fake;int vis[2090],dis[2090];ll f[2090];int e[2090][2090];void spfa(){ memset(dis,63,sizeof(dis)); fake=dis[233]; queue
q; q.push(1);vis[1]=1;dis[1]=0;f[1]=1; while(!q.empty()) { int u=q.front();q.pop(); vis[u]=0; if(u==n) continue; for(int i=1;i<=n;i++) { if(dis[i]==dis[u]+e[u][i]) f[i]+=f[u]; if(dis[i]>dis[u]+e[u][i]) { dis[i]=dis[u]+e[u][i]; f[i]=f[u]; } if(f[i]&&!vis[i]) vis[i]=1,q.push(i); } f[u]=0; }}int main(){ scanf("%d%d",&n,&m); memset(e,63,sizeof(e)); for(int i=1;i<=m;i++) { int x=0,y=0,z=0; scanf("%d%d%d",&x,&y,&z); e[x][y]=min(e[x][y],z); } spfa(); if(fake==dis[n]) printf("No answer"); else printf("%d %lld",dis[n],f[n]); return 0;}
View Code

以上是过世算法$spfa$,现在我来为大家表演一下$dijkstra$。(搬运逛公园的30部分分)dij不用清空,非常优秀。

1 #include
2 #include
3 #include
4 #include
5 #define maxn 100090 6 7 using namespace std; 8 typedef long long ll; 9 10 int T,n,m,k,tot;11 int head[maxn];12 bool vis[maxn];13 ll moder,f[maxn],dis[maxn];14 struct node{15 int to,next,val;16 }edge[maxn<<2];17 18 void add(int x,int y,int z)19 {20 edge[++tot].to=y;21 edge[tot].next=head[x];22 head[x]=tot;23 edge[tot].val=z;24 }25 26 void Clear()27 {28 tot=0;29 memset(head,0,sizeof(head));30 memset(vis,0,sizeof(vis));31 memset(f,0,sizeof(f));32 }33 34 void dijkstra()35 {36 priority_queue
>q;37 for(int i=1;i<=n;i++) dis[i]=3e9;38 q.push(make_pair(0,1));dis[1]=0;f[1]=1;39 while(!q.empty())40 {41 int u=q.top().second;q.pop();42 if(vis[u]) continue;43 vis[u]=1;44 for(int i=head[u];i;i=edge[i].next)45 {46 int v=edge[i].to;47 if(dis[v]>dis[u]+edge[i].val)48 {49 dis[v]=dis[u]+edge[i].val;50 q.push(make_pair(-dis[v],v));51 (f[v]=f[u])%=moder;52 }53 else if(dis[v]==dis[u]+edge[i].val)54 (f[v]+=f[u])%=moder;55 }56 }57 }58 59 int main()60 {61 scanf("%d",&T);62 while(T--)63 {64 scanf("%d%d%d%lld",&n,&m,&k,&moder);65 for(int i=1;i<=m;i++)66 {67 int x=0,y=0,z=0;68 scanf("%d%d%d",&x,&y,&z);69 add(x,y,z);70 }71 dijkstra();72 // if(dis[n]==3e9) printf("-1");73 printf("%lld\n",f[n]);74 //for(int i=1;i<=n;i++) printf("%lld ",dis[i]);75 Clear();76 }77 return 0;78 }
Counting
  • kruskal算法求最小生成树:基于边。比较好理解,先对所有边进行排序,用并查集维护联通关系。复杂度为$O(mlogm)$。(其实不用找到n-1条边就退出...)
1 /* 2 最小生成树Kruskal算法 3 快排权值+并查集看是否连通 4 */  5 #include
6 #include
7 8 using namespace std; 9 10 int n,m,cnt,ans;11 int fa[5090];12 struct node{13 int f,t,w;14 }edge[400090];15 16 bool cmp(node a,node b)17 {18 return a.w
Kruskal
  • Prim算法求最小生成树:基于点,逐步扩展。随便找一个点作为起点,设$dis$为添加了这个点需要增加的边权,然后每次在尚未被进入生成树的节点中寻找最小的$dis$,记录它的位置,这一次就把他加入生成树,并更新其他点的$dis$。复杂度$O(n^2)$。注意是否$vis$。
1 #include
2 #include
3 #include
4 #define maxn 5090 5 6 using namespace std; 7 typedef long long ll; 8 9 int n,m,tot;10 ll ans;11 int head[maxn],dis[maxn],vis[maxn];12 struct node{13 int to,next,val;14 }edge[400090];15 16 void add(int x,int y,int z)17 {18 edge[++tot].to=y;19 edge[tot].next=head[x];20 head[x]=tot;21 edge[tot].val=z;22 }23 24 void prim()25 {26 memset(dis,127,sizeof(dis));27 dis[1]=0;28 for(int k=1;k<=n;k++)29 {30 int u=-1,sta=0x3f3f3f3f;31 for(int i=1;i<=n;i++)32 if(dis[i]
Prim
  • 树的直径方法一:两遍bfs/dfs【不能处理有负权边情况】【记录路径】
1 int bfs(int x) 2 { 3     queue
q; 4 memset(d,0x3f,sizeof(d)); 5 memset(pre,0,sizeof(pre)); 6 fake=d[233]; 7 q.push(x);d[x]=0; 8 while(!q.empty()) 9 {10 int u=q.front();q.pop();11 for(int i=head[u];i;i=edge[i].next)12 {13 int v=edge[i].to;14 if(d[v]==fake) q.push(v),pre[v]=i,d[v]=d[u]+1;15 }16 }17 int top=x;18 for(int i=1;i<=n;i++)19 if(d[i]>d[top]) top=i;20 return top; 21 }22 int get_d()23 {24 p=bfs(1);25 p=bfs(p);26 return d[p];27 }
Tree's Diameter/BFS
  • 树的直径方法二:树形dp
1 void Treedp(int u) 2 { 3     vis[u]=1; 4     for(int i=head[u];i;i=edge[i].next) 5     { 6         int v=edge[i].to; 7         if(vis[v]) continue; 8         Treedp(v); 9         ans=max(ans,f[x]+f[y]+edge[i].val)10         f[x]=max(f[x],f[y]+edge[i].val);11     }12 }
Tree's Diameter/Treedp
  • 强连通分量/缩点(in有向图)
1 void tarjan(int u) 2 { 3     dfn[u]=low[u]=++dfs_clock; 4     st.push(u); 5     for(int i=head[u];i;i=edge[i].next) 6     { 7         int v=edge[i].to; 8         if(!dfn[v]) 9         {10             tarjan(v);11             low[u]=min(low[u],low[v]);12         }13         else if(!scc[v]) low[u]=min(low[u],dfn[v]);14     }15     if(low[u]==dfn[u])16     {17         scc_cnt++;18         while(1)19         {20             int x=st.top();st.pop();21             scc[x]=scc_cnt;22             if(x==u) break;23         }24     }25 }26 —————————————————————————————————————27     for(int i=1;i<=n;i++)//在主程序中28         if(!dfn[i]) tarjan(i);29     for(int x=1;x<=n;x++)30         for(int i=head[x];i;i=edge[i].next)31         {32             int y=edge[i].to;33             if(scc[x]!=scc[y])34                 ADD(scc[x],scc[y]);35         }
tarjan1
  • 树上倍增求LCA

1 #include
2 #include
3 #include
4 #include
5 #define maxn 500090 6 7 using namespace std; 8 9 int n,m,s,tot,t;10 int d[maxn],head[maxn],f[maxn][31];11 struct node{12 int to,next;13 }edge[maxn<<1];14 15 void add(int x,int y)16 {17 edge[++tot].to=y;18 edge[tot].next=head[x];19 head[x]=tot;20 }21 22 void init()23 {24 queue
q;25 q.push(s);d[s]=1;26 while(!q.empty())27 {28 int u=q.front();q.pop();29 for(int i=head[u];i;i=edge[i].next)30 {31 int v=edge[i].to;32 if(d[v]) continue;33 d[v]=d[u]+1;34 f[v][0]=u;35 for(int j=1;j<=t;j++)36 f[v][j]=f[f[v][j-1]][j-1];37 q.push(v);38 }39 }40 }41 42 int lca(int x,int y)43 {44 if(d[x]
=0;i--) 46 if(d[f[x][i]]>=d[y]) x=f[x][i];47 if(x==y) return x;48 for(int i=t;i>=0;i--)49 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];50 return f[x][0];51 }52 53 int main()54 {55 scanf("%d%d%d",&n,&m,&s);56 t=log2(n)+1;57 for(int i=1;i<=n-1;i++)58 {59 int x=0,y=0;60 scanf("%d%d",&x,&y);61 add(x,y),add(y,x);62 }63 init();64 for(int i=1;i<=m;i++)65 {66 int x=0,y=0;67 scanf("%d%d",&x,&y);68 printf("%d\n",lca(x,y));69 }70 return 0;71 }
LCA

字符串

  • $trie$树
1 tot=0; 2 void insert() 3 { 4     int p=0; 5     int len=strlen(tmp+1); 6     for(int i=1;i<=len;i++) 7     { 8         int qwq=tmp[i]-'0'; 9         if(!trie[p][qwq]) trie[p][qwq]=++tot;10         p=trie[p][qwq];11     }12 }
trie--insert
  •  最小表示法
1 void work() 2 { 3     n=strlen(str+1);ans=0; 4     for(int i=1;i<=n;i++) str[n+i]=str[i]; 5     int i=1,j=2,k; 6     while(i<=n&&j<=n) 7     { 8         for(k=0;k<=n&&str[i+k]==str[j+k];k++); 9         if(k>=n) break;10         if(str[i+k]>str[j+k])11         {i=i+k+1;if(i==j) i++;}12         else13         {j=j+k+1;if(i==j) j++;}14     }15     ans=min(i,j);16     printf("%d\n",ans);17 }18 //注意数组开二倍+
Minimal Expression

 

其他技巧

  • 编译命令:-Wshadow -Wconversion  -Wextra / 打开wall警告开关
  • 简单重载运算符:
  • 更多有关$lowerbound$和$upperbound$:
  • 生成数据前,一定要记得调用种子!!即(在挂文件后)
srand(time(NULL));
  • 生成数据的批处理文件($bat$)
1 @echo off 2 :loop 3  4 rand.exe 5  6 baoli.exe 7  8 sol.exe 9 10 fc baoli.out sol.out11 12 if not errorlevel 1 goto loop13 14 pause 15 16 goto loop
dp.bat
  • 生成数据
1 int random(int lim)2 {3     return (unsigned long long)rand()*rand()%lim; 4 }5 6 7 调用时:int x=random(100)+1;
rand

 

看到小数据范围:暴搜 全排列 二进制枚举  状压

$O(n^3)$:考虑枚举区间?

转载于:https://www.cnblogs.com/nopartyfoucaodong/p/9652145.html

你可能感兴趣的文章
ubuntu 刚更改默认python3版本后更新包等
查看>>
quartz教程三
查看>>
利用saltstack初始化OpenStack服务器环境
查看>>
python连接数据库并插入数据
查看>>
Log4net使用笔记
查看>>
查询更新的表结构
查看>>
menustrip
查看>>
RSync实现文件备份同步
查看>>
数据导入到excel表中
查看>>
OptimalSolution(6)--栈和队列
查看>>
php运算符
查看>>
[LintCode] Binary Search Tree Iterator
查看>>
[补档]happiness
查看>>
封装计算方法实现面向对象计算器。
查看>>
Python入门教程 超详细1小时学会Python
查看>>
JS对象创建常用方式及原理分析
查看>>
定时压缩日志文件并发送到邮箱
查看>>
postgresql 一些操作
查看>>
《深入浅出深度学习:原理剖析与python实践》第八章前馈神经网络(笔记)
查看>>
linux shell中读写操作mysql数据库
查看>>