NOIp知识集合 By cellur925
基本算法
- 快速幂
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 }
- 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 }
- 离散化
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;
- 归并排序求逆序对
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 }
- 全排列
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 }
- ST表
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 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<<k)+1][k]); 14 } 15 16 int main() 17 { 18 scanf("%d%d",&n,&m); 19 for(int i=1;i<=n;i++) scanf("%d",&st[i][0]); 20 for(int j=1;j<=30;j++) 21 for(int i=1;i+(1<<j)-1<=n;i++) 22 st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]); 23 for(int i=1;i<=m;i++) 24 { 25 int l=0,r=0; 26 scanf("%d%d",&l,&r); 27 printf("%d\n",sta(l,r)); 28 } 29 return 0; 30 }
- 两种二分
1 while(l<r) 2 { 3 int mid=(l+r)>>1; 4 if(check(mid)) r=mid; 5 else l=mid+1; 6 } 7 while(l<r) 8 { 9 int mid=(l+r+1)>>1; 10 if(check(mid)) r=mid-1; 11 else l=mid; 12 }
1 double eps=1e-8; 2 while(l+eps<r) 3 { 4 double mid=(l+r)/2; 5 if(check(mid)) r=mid; 6 else l=mid; 7 }
- 康拓展开及其求逆 推荐文章
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]<a[i]) tot++; 30 ans+=1ll*tot*fac[n-i]; 31 } 32 return ans; 33 }
其他算法
- 莫队算法(不带修)
1 bool cmp(query a,query b) 2 { 3 return (a.l/block)^(b.l/block) ? a.l<b.l : (((a.l/block)&1) ? a.r<b.r : a.r>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<l) remove(posl++); 21 while(posr>r) remove(posr--); 22 while(posl>l) add(--posl); 23 while(posr<r) add(++posr); 24 ans[ask[i].id]=noww; 25 } 26 for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
数学
- 预处理阶乘和处理逆元求组合数
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 }
-
杨辉三角求组合数
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;
数据结构
- $vector$实现普通平衡树 慎用!!!
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 5 using namespace std; 6 7 int n; 8 vector<int>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 */
图论
- 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]);
- Dijkstra+堆优化。复杂度$O(mlogn)$。稠密图优。好像不能用来跑最长路诶(
1 void dijkstra() 2 { 3 priority_queue<pair<int,int> >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 }
- spfa过世算法复杂度理解为$O(nm)$。但稀疏图$O(km)$。
1 void spfa() 2 { 3 memset(dis,0x3f,sizeof(dis)); 4 queue<int>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 }
- 判断树上两路径是否相交
* 题目:LuoguP3398仓鼠找sugar / 计蒜客NOIP提高组模拟一试T2 敌对势力 / hihocoder 11D(题目找不到了==可以看这位dalao的博客)
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cmath> 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<int>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 }
- 最短路计数
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> 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<int>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; }
以上是过世算法$spfa$,现在我来为大家表演一下$dijkstra$。(搬运逛公园的30部分分)dij不用清空,非常优秀。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 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<pair<ll,int> >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 }
- kruskal算法求最小生成树:基于边。比较好理解,先对所有边进行排序,用并查集维护联通关系。复杂度为$O(mlogm)$。(其实不用找到n-1条边就退出...)
1 /* 2 最小生成树Kruskal算法 3 快排权值+并查集看是否连通 4 */ 5 #include<cstdio> 6 #include<algorithm> 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<b.w; 19 } 20 21 int getf(int x) 22 { 23 if(x==fa[x]) return x; 24 return fa[x]=getf(fa[x]); 25 } 26 27 int main() 28 { 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=m;i++) 31 scanf("%d%d%d",&edge[i].f,&edge[i].t,&edge[i].w); 32 for(int i=1;i<=n;i++) fa[i]=i; 33 sort(edge+1,edge+1+m,cmp); 34 for(int i=1;i<=m;i++) 35 { 36 if(cnt==n-1) break; 37 int pp=getf(edge[i].f); 38 int qq=getf(edge[i].t); 39 if(pp==qq) continue; 40 fa[qq]=pp; 41 cnt++; 42 ans+=edge[i].w; 43 } 44 if(cnt<n-1) printf("orz"); 45 else printf("%d\n",ans); 46 return 0; 47 }
- Prim算法求最小生成树:基于点,逐步扩展。随便找一个点作为起点,设$dis$为添加了这个点需要增加的边权,然后每次在尚未被进入生成树的节点中寻找最小的$dis$,记录它的位置,这一次就把他加入生成树,并更新其他点的$dis$。复杂度$O(n^2)$。注意是否$vis$。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 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]<sta&&!vis[i]) sta=dis[i],u=i; 33 if(u==-1) {printf("orz\n");exit(0);} 34 ans+=dis[u]; 35 vis[u]=1; 36 for(int i=head[u];i;i=edge[i].next) 37 { 38 int v=edge[i].to; 39 if(vis[v]) continue; 40 dis[v]=min(dis[v],edge[i].val); 41 } 42 } 43 } 44 45 int main() 46 { 47 scanf("%d%d",&n,&m); 48 for(int i=1;i<=m;i++) 49 { 50 int x=0,y=0,z=0; 51 scanf("%d%d%d",&x,&y,&z); 52 add(x,y,z);add(y,x,z); 53 } 54 prim(); 55 printf("%d\n",ans); 56 return 0; 57 }
- 树的直径方法一:两遍bfs/dfs【不能处理有负权边情况】【记录路径】
1 int bfs(int x) 2 { 3 queue<int>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 }
- 树的直径方法二:树形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 }
- 强连通分量/缩点(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 }
-
树上倍增求LCA
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cmath> 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<int>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]<d[y]) swap(x,y); 45 for(int i=t;i>=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 }
字符串
- $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 }
- 最小表示法
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 else 13 {j=j+k+1;if(i==j) j++;} 14 } 15 ans=min(i,j); 16 printf("%d\n",ans); 17 } 18 //注意数组开二倍+
其他技巧
- 编译命令:-Wshadow -Wconversion -Wextra / 打开wall警告开关
- 简单重载运算符:https://www.cnblogs.com/nopartyfoucaodong/p/9734314.html
- 更多有关$lowerbound$和$upperbound$:https://www.cnblogs.com/nopartyfoucaodong/p/9818967.html
- 生成数据前,一定要记得调用种子!!即(在挂文件后)
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.out 11 12 if not errorlevel 1 goto loop 13 14 pause 15 16 goto loop
- 生成数据
1 int random(int lim) 2 { 3 return (unsigned long long)rand()*rand()%lim; 4 } 5 6 7 调用时:int x=random(100)+1;
看到小数据范围:暴搜 全排列 二进制枚举 状压
$O(n^3)$:考虑枚举区间?
独立意志与自由思想是必须争的,且须以生死力争。