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 } 
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<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 }
ST Table
  • 两种二分
 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 }
Cantor&Recantor

其他算法

  • 莫队算法(不带修)
 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]);
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<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 */
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<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 }
Dijkstra+Heap
  • 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 }
spfa
  • 判断树上两路径是否相交

*  题目: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 }
View Code
  • 最短路计数
#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;
}
View Code

以上是过世算法$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 }
Counting
  • 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 }
Kruskal
  • 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 } 
Prim
  • 树的直径方法一:两遍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 }
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<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 } 
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         else
13         {j=j+k+1;if(i==j) j++;}
14     }
15     ans=min(i,j);
16     printf("%d\n",ans);
17 }
18 //注意数组开二倍+
Minimal Expression

 

其他技巧

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
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)$:考虑枚举区间?

posted @ 2018-10-13 21:27  cellur925&Chemist  阅读(924)  评论(0编辑  收藏  举报