一些理解加记住的板子们(知识理解)

tarjan求有向图强联通分量,缩点

 1 //有向图求强联通分量,缩点
 2 int head[110000],nex[110000],to[110000],tot;
 3 int dfn[110000],low[110000],st[110000],inst[110000],belong[110000],num,cnt;
 4 vector<int>vcc[110000];
 5 void tarjan(int x,int pre){
 6     dfn[x]=low[x]=++num;
 7     st[++st[0]]=x,inst[x]=1;
 8     for(register int i=head[x];i;i=nex[i]){
 9         int y=to[i];
10         if(y==pre) continue;
11         if(!dfn[y]){
12             tarjan(y,x);
13             low[x]=min(low[x],low[y]);
14         }
15         else if(inst[y]) low[x]=min(low[x],dfn[y]);
16     }
17     if(low[x]==dfn[x]){
18         ++cnt;int y;
19         do{
20             y=st[st[0]--];
21             inst[y]=0;
22             belong[y]=cnt;
23             vcc.push_back(y);
24         }while(y!=x);
25     }
26 }
View Code

高精度板子

 1 struct Big{
 2     int len,s[110000];
 3     Big(){memset(s,0,sizeof(s)),len=1;}
 4     Big(register int val){*this=val;}
 5     Big(const char *val){*this=val;}
 6     Big operator = (const int &val){
 7         char s[110000];
 8         sprintf(s,"%d",val);
 9         *this=s;return *this;
10     }
11     Big operator = (const char *val){
12         len=strlen(val);
13         while(len>1&&val[0]=='0') ++val,len--;
14         for(register int i=0;i<len;++i) s[i]=val[len-i-1]-'0';
15         return *this;
16     }
17     inline void deal(){
18         while(len>1&&!s[len-1]) len--;
19     }
20     Big operator + (const Big &a)const{
21         Big res;res.len=0;
22         int top=max(len,a.len),add=0;
23         for(register int i=0;add||i<top;++i){
24             int now=add;
25             if(i<len) now+=s[i];
26             if(i<a.len) now+=a.s[i];
27             res.s[res.len++]=now%10;
28             add=now/10;
29         }
30         return res;
31     }
32     Big operator - (const Big &a)const{
33         Big res;res.len=0;int del=0;
34         for(register int i=0;i<len;++i){
35             int now=s[i]-del;
36             if(i<a.len) now-=a.s[i];
37             if(now>=0) del=0;
38             else del=1,now+=10;
39             res.s[res.len++]=now;
40         }
41         res.deal();return res;
42     }
43     Big operator * (const Big &a)const{
44         Big res;res.len=len+a.len;
45         for(register int i=0;i<len;i++)
46             for(register int j=0;j<a.len;j++)
47                 res.s[i+j]+=s[i]*a.s[j];
48         for(register int i=0;i<res.len;i++)
49             res.s[i+1]+=res.s[i]/10,res.s[i]%=10;
50         res.deal();return res;
51     }
52     Big operator / (const Big &a)const{
53         Big res,cur=0;res.len=len;
54         for(register int i=len-1;~i;i--){
55             cur=cur*Big(10),cur.s[0]=s[i];
56             while(cur>=a) cur-=a,res.s[i]++;
57         }
58         res.deal();return res;
59     }
60     Big operator % (const Big &a)const{
61         Big res=*this/a;
62         return *this-res*a;
63     }
64     Big operator += (const Big &a){ *this=*this+a; return *this;}
65     Big operator -= (const Big &a){ *this=*this-a; return *this;}
66     Big operator *= (const Big &a){ *this=*this*a; return *this;}
67     Big operator /= (const Big &a){ *this=*this/a; return *this;}
68     Big operator %= (const Big &a){ *this=*this%a; return *this;}
69     bool operator < (const Big &a)const{
70         if(len!=a.len) return len<a.len;
71         for(register int i=len-1;~i;i--)
72             if(s[i]!=a.s[i]) return s[i]<a.s[i];
73         return 0;
74     }
75     bool operator > (const Big &a)const{return a<*this;}
76     bool operator <= (const Big &a)const{return !(*this>a);}
77     bool operator >= (const Big &a)const{return !(*this<a);}
78     bool operator == (const Big &a) const{return !(*this<a||*this>a);}
79     bool operator != (const Big &a)const{return *this<a||*this>a;}
80 };
81 void print(Big w){
82     for(register int i=w.len-1;~i;i--)
83         printf("%d",w.s[i]);
84     puts("");
85 }
View Code

线性求逆元

inv[1]=1;
for(register int i=2;i<=n;i++) inv[i]=1ll*(p-p/i)*inv[p%i]%p;

线性筛欧拉函数值

phi[1]=1;
for(register int i=2;i<=n;i++){
    if(!v[i]) prm[++prm[0]]=i,phi[i]=i-1;
    for(register int j=1;j<=prm[0]&&i*prm[j]<=n;j++){
        v[i*prm[j]]=1;
        if(i%prm[j]) phi[i*prm[j]]=phi[i]*(prm[j]-1);
        else{
            phi[i*prm[j]]=phi[i]*prm[j];
            break;
        }
    }
}

快速幂+线性筛(快速求1~n的k次幂,n=1e7,O(nlog)卡不过去)

mi[1]=1;
for(register int i=2;i<=n;i++){
    if(!v[i]) prm[++prm[0]]=i,mi[i]=qpow(i,k);
    for(register int j=1;j<=prm[0]&&i*prm[j]<=n;j++){
        v[i*prm[j]]=1;
        mi[i*prm[j]]=mi[i]*mi[prm[j]]%mod;
        if(i%prm[j]==0) break;        
    }
}

  拓展 快速幂+线性筛 求$\sum\limits_{i=1}^{n}i^k \% m$ n=1e18 m=3e6

    利用上面的线筛筛出1~m的k次幂

    然后化式子为$\sum\limits_{i=1}^{n}(i\%m)^k \% m$ ,1~m的k次幂加和乘上循环节个数再加上末尾余下的几个k次幂

平方和公式

  $\large\sum\limits_{i=1}^{n} i^2=\frac{n*(n+1)*(2*n+1)}{6}$

树链剖分(线段树维护DFS序)

 1 int n,to[21000],nex[21000],head[11000],len[21000],tot=1;
 2 int dfn[11000],top[11000],size[11000],rk[11000],c[11000],cet,fa[11000],son[11000],dis[11000];
 3 int maxn[41000];
 4 void add(int x,int y,int z){
 5     to[++tot]=y,nex[tot]=head[x],head[x]=tot,len[tot]=z;
 6 }
 7 void dfs(int x,int pre){
 8     size[x]=1;
 9     top[x]=x;
10     fa[x]=pre;
11     dis[x]=dis[pre]+1;
12     for(register int i=head[x];i;i=nex[i]){
13         int y=to[i];
14         if(y==pre) continue;
15         c[y]=len[i],len[i^1]=len[i]=y;
16         dfs(y,x);
17         son[x]=size[son[x]]>size[y]?son[x]:y;
18         size[x]+=size[y];
19     }
20 }
21 void DFS(int x,int pre){
22     dfn[x]=++cet;
23     rk[cet]=x;
24     if(son[x]) top[son[x]]=top[x],DFS(son[x],x);
25     for(register int i=head[x];i;i=nex[i]){
26         int y=to[i];
27         if(y==pre||y==son[x]) continue;
28         DFS(y,x);
29     }
30 }
31 void build(int t,int l,int r){
32     if(l==r){
33         maxn[t]=c[rk[l]];
34         return;
35     }
36     int mid=(l+r)>>1;
37     build(t*2,l,mid);
38     build(t*2+1,mid+1,r);
39     maxn[t]=max(maxn[t*2],maxn[t*2+1]);
40 }
41 void change(int t,int l,int r,int x,int k){
42     if(l==r){
43         maxn[t]=k;
44         return;
45     }
46     int mid=(l+r)>>1;
47     if(mid>=x) change(t*2,l,mid,x,k);
48     else change(t*2+1,mid+1,r,x,k);
49     maxn[t]=max(maxn[t*2],maxn[t*2+1]);
50 }
51 int ask(int t,int l,int r,int L,int R){
52     if(L>R) return 0;
53     if(L<=l&&r<=R)    return maxn[t];
54     int mid=(l+r)>>1,ans=0;
55     if(mid>=L) ans=max(ans,ask(t*2,l,mid,L,R));
56     if(mid<R) ans=max(ans,ask(t*2+1,mid+1,r,L,R));
57     return ans;
58 }
59 int query(int x,int y){
60     int xx=top[x],yy=top[y],ans=0;
61     while(xx!=yy){
62         if(dis[xx]>dis[yy]) ans=max(ans,ask(1,1,n,dfn[xx],dfn[x])),x=fa[xx],xx=top[x];
63         else ans=max(ans,ask(1,1,n,dfn[yy],dfn[y])),y=fa[yy],yy=top[y];
64     }
65     if(dis[x]>dis[y]) swap(x,y);
66     ans=max(ans,ask(1,1,n,dfn[x]+1,dfn[y]));
67     return ans;
68 }
难存的情缘的树剖部分

数位DP

 1 int a[20],dp[20][2];
 2 int dfs(int pos,int pre,int sta,bool limit){
 3     if(pos==-1) return 1;
 4     if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
 5     int up=limit?a[pos]:9;
 6     int ans=0;
 7     for(int i=0;i<=up;i++){
 8         if(pre==6&&i==2) continue;
 9         if(i==4) continue;
10         ans+=dfs(pos-1,i,i==6,limit&&i==a[pos]);
11     }
12     if(!limit) dp[pos][sta]=ans;
13     return ans;
14 }
15 int solve(int x){
16     int pos=0;
17     while(x){
18         a[pos++]=x%10;
19         x/=10;
20     }
21     return dfs(pos-1,-1,0,true);
22 }
View Code

KD-Tree

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,maximum,minimum,sz,now,ans;
struct Point{
    int x[2];
}sour[510000];
int comp(Point a,Point b){
    return a.x[now]<b.x[now];
}
int dis(Point a,Point b){
    return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]); 
}
struct KD_Tree{
    KD_Tree *ch[2];
    Point ponit;
    int maxn[2],minn[2];
    void redef(Point a){
        ponit=a,minn[0]=maxn[0]=a.x[0],minn[1]=maxn[1]=a.x[1],ch[0]=ch[1]=NULL;
    }
    void update(KD_Tree *a){
        minn[0]=min(minn[0],a->minn[0]),maxn[0]=max(maxn[0],a->maxn[0]);
        minn[1]=min(minn[1],a->minn[1]),maxn[1]=max(maxn[1],a->maxn[1]);
    }
    void pushup(){
        if(ch[0]) update(ch[0]);
        if(ch[1]) update(ch[1]);
    }
    int calc_min(Point a){
        return max(minn[0]-a.x[0],0)+max(a.x[0]-maxn[0],0)+max(minn[1]-a.x[1],0)+max(a.x[1]-maxn[1],0);
    }
    int calc_max(Point a){
        return max(abs(a.x[0]-minn[0]),abs(a.x[0]-maxn[0]))+max(abs(a.x[1]-minn[1]),abs(a.x[1]-maxn[1]));
    }
}*root,tr[510000];
void build(KD_Tree *&p,int l,int r,int d){
    if(l>r) return;
    p=tr+(sz++),now=d;
    nth_element(sour+l,sour+((l+r)/2),sour+(r+1),comp);
    p->redef(sour[((l+r)/2)]);
    build(p->ch[0],l,((l+r)/2)-1,d^1);
    build(p->ch[1],((l+r)/2)+1,r,d^1);
    p->pushup();  
    
}
void query_max(KD_Tree *p,Point cmp){
    if(p==NULL) return;
    maximum=max(dis(p->ponit,cmp),maximum);
    int Dis[2]={p->ch[0]==NULL?0:p->ch[0]->calc_max(cmp),p->ch[1]==NULL?0:p->ch[1]->calc_max(cmp)};
    int first=Dis[0]>Dis[1]?0:1;
    if(Dis[first]>maximum) query_max(p->ch[first],cmp);
    if(Dis[first^1]>maximum) query_max(p->ch[first^1],cmp);
}
void query_min(KD_Tree *p,Point cmp){
    if(p==NULL) return;
    if(dis(p->ponit,cmp)) minimum=min(dis(p->ponit,cmp),minimum);
    int Dis[2]={p->ch[0]==NULL?0x7f7f7f7f:p->ch[0]->calc_min(cmp),p->ch[1]==NULL?0x7f7f7f7f:p->ch[1]->calc_min(cmp)};
    int first=Dis[0]<Dis[1]?0:1;
    if(Dis[first]<minimum) query_min(p->ch[first],cmp);
    if(Dis[first^1]<minimum) query_min(p->ch[first^1],cmp); 
}
int query_max(Point cmp){
    maximum=0,query_max(root,cmp);
    return maximum;
}
int query_min(Point cmp){
    minimum=0x7fffffff,query_min(root,cmp);
    return minimum;
}
int main(){
    scanf("%d",&n);
    ans=0x7f7f7f7f;
    for(int i=1;i<=n;i++) scanf("%d%d",&sour[i].x[0],&sour[i].x[1]);
    build(root,1,n,0);
    for(int i=1;i<=n;i++){
        ans=min(ans,query_max(sour[i])-query_min(sour[i]));
    }
    printf("%d\n",ans);
}
捉迷藏

插头DP

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m;
    const int mod=2601,p=1e9;
    struct node{
        int bit[10];
        void clear(){memset(bit,0,sizeof(bit));}
        node operator + (node b){
            node c;c.clear();
            c.bit[0]=max(b.bit[0],bit[0])+1;
            for(int i=1;i<=c.bit[0];i++){
                c.bit[i]+=b.bit[i]+bit[i],c.bit[i+1]=c.bit[i]/p,c.bit[i]%=p;
            }
            while(!c.bit[c.bit[0]]) c.bit[0]--;
            return c;
        }
        void operator += (node b){*this=*this+b;}
    }ans;
    struct Hash{
        int key[2601],hash[2601],size;
        node val[2601];
        void clear(){
            size=0;
            memset(key,-1,sizeof(key));
            memset(val,0,sizeof(val));
            memset(hash,0,sizeof(hash));
        }
        void insert(const int state,node c){
            for(int i=state%mod;;i=(i+1==mod)?0:i+1){
                if(!hash[i]){
                    hash[i]=++size;
                    key[size]=state;
                    val[size].clear();
                    val[size]+=c;
                    return;    
                }
                if(key[hash[i]]==state){
                    val[hash[i]]+=c;
                    return;
                }
            }
        }
    }f[2];
    int set(int &state,int y,int s){
        state|=(3<<((y-1)<<1));
        state^=((3^s)<<((y-1)<<1));
    }
    int find(int state,int pos){
        int s=state>>((pos-1)<<1)&3;
        int cnt=0,i,t=(s==1)?1:-1;
        for(i=pos;i&&i<=m+1;i+=t){
            int w=state>>((i-1)<<1)&3;
            if(w==1) cnt++;
            else if(w==2) cnt--;
            if(cnt==0) return i;
        }
        return -1;
    }
    int main(){
        ans.clear();
        scanf("%d%d",&n,&m);
        if(n==1||m==1){
            printf("1\n");
            return 0;
        }
        if(n<m) swap(n,m);
        int cur=0;
        f[cur].clear();
        node a; a.clear();
        a.bit[++a.bit[0]]=1;
        f[0].insert(0,a);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cur^=1;
                f[cur].clear();
                int upw=f[cur^1].size;
                for(int k=1;k<=upw;k++){
                    int last=f[cur^1].key[k];
                    node val;val.clear();
                    val+=f[cur^1].val[k];
                    int plug1=(last>>((j-1)<<1))&3,plug2=(last>>(j<<1))&3;
                    if(last<0) return 0;
                    //if(find(last,j)==-1||find(last,j+1)==-1) continue;
                    if(!plug1&&!plug2){
                        if(i!=n&&j!=m){
                            set(last,j,1);
                            set(last,j+1,2);
                            f[cur].insert(last,val);
                        }
                    }
                    else if(plug1&&!plug2){
                        if(i!=n) f[cur].insert(last,val);
                        if(j!=m) set(last,j,0),set(last,j+1,plug1),f[cur].insert(last,val);
                    }
                    else if(!plug1&&plug2){
                        if(j!=m) f[cur].insert(last,val);
                        if(i!=n) set(last,j+1,0),set(last,j,plug2),f[cur].insert(last,val);
                    }
                    else if(plug1==1&&plug2==1){
                        set(last,find(last,j+1),1),set(last,j,0),set(last,j+1,0),f[cur].insert(last,val);
                    }
                    else if(plug1==1&&plug2==2){
                        if(i==n&&j==m) ans+=val;
                    }
                    else if(plug1==2&&plug2==2){
                        set(last,find(last,j),2),set(last,j,0),set(last,j+1,0),f[cur].insert(last,val);
                    }
                    else if(plug1==2&&plug2==1){
                        set(last,j,0),set(last,j+1,0),f[cur].insert(last,val);
                    }
                }
                
            }
            if(i!=n){
                int now=(i*m)&1,tot=f[now].size;
                for(int j=1;j<=tot;j++)
                    f[now].key[j]<<=2;
            }
        }
        ans+=ans;
        printf("%d",ans.bit[ans.bit[0]]);
        for(int i=ans.bit[0]-1;i>=1;i--) printf("%09d",ans.bit[i]);
    }
以邮递员为例

手写堆

int match[110000],top;//match 记录某一个值所在堆中的标号
struct Queue{
    int val,pos;
    Queue(int a=0,int b=0){val=a,pos=b;}
}h[110000];
inline void up(int i){
    //while(i>1&&h[i].val<h[i>>1].val)//小根堆
    while(i>1&&h[i].val>h[i>>1].val)//大根堆
        match[h[i>>1].pos]=i,swap(h[i>>1],h[i]),i>>=1;
    
    match[h[i].pos]=i;
}
inline void down(int i){
    int to;
    while((i<<1)<=top){
        to=(i<<1);
    //  if(to<top&&h[to+1].val<h[to].val) ++to; //小根堆
        if(to<top&&h[to+1].val>h[to].val) ++to; //大根堆
    //    if(h[to].val<h[i].val)//小根堆
        if(h[to].val>h[i].val) //大根堆
            match[h[to].pos]=i,swap(h[i],h[to]),i=to;
        else break;
    }
    match[h[i].pos]=i;
}
inline void push(int val,int pos){h[++top]=Queue(val,pos);up(top);}
inline void pop(int i){
    //h[i].val=0x7fffffff; //小根堆
    h[i].val=-0x7fffffff;//大根堆
    down(i);
}
View Code

CDQ分治

    void CDQ(int l,int r){
        if(l==r) return;
        int mid=(l+r)/2,i=l,j=mid+1,p=l;
        CDQ(l,mid),CDQ(mid+1,r);
        while(i<=mid&&j<=r){
            //if(v[j].id==2||v[j].id==3) cout<<v[j].id<<" "<<ask(v[j].c)<<endl;
            if(v[i].b<=v[j].b) add(v[i].c,v[i].cnt),tmp[p++]=v[i++];
            else num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++];
        }
        while(i<=mid) add(v[i].c,v[i].cnt),tmp[p++]=v[i++];
        while(j<=r) num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++];
        for(int k=l;k<=mid;k++) add(v[k].c,-v[k].cnt); 
        for(int k=l;k<=r;k++) v[k]=tmp[k];
    }
CDQ函数
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,tr[210000],num[110000],ans[110000];
    struct node{
        int a,b,c,id,cnt;
    }w[110000],v[110000],tmp[110000];
    int cmp(node x,node y){
        return x.a==y.a?((x.b==y.b)?(x.c<y.c):(x.b<y.b)):x.a<y.a;
    }
    int lowbit(int x){return x&(-x);}
    void add(int x,int k){
        while(x<=m){
            tr[x]+=k;
            x+=lowbit(x);
        }
    }
    int ask(int x){
        int ans=0;
        while(x){
            ans+=tr[x];
            x-=lowbit(x);
        }
        return ans;
    }
    void CDQ(int l,int r){
        if(l==r) return;
        int mid=(l+r)/2,i=l,j=mid+1,p=l;
        CDQ(l,mid),CDQ(mid+1,r);
        while(i<=mid&&j<=r){
            //if(v[j].id==2||v[j].id==3) cout<<v[j].id<<" "<<ask(v[j].c)<<endl;
            if(v[i].b<=v[j].b) add(v[i].c,v[i].cnt),tmp[p++]=v[i++];
            else num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++];
        }
        while(i<=mid) add(v[i].c,v[i].cnt),tmp[p++]=v[i++];
    //    cout<<l<<" "<<mid<<" "<<r<<" "<<tr[1]<<" "<<tr[2]<<" "<<tr[3]<<endl; 
        while(j<=r) num[v[j].id]+=ask(v[j].c),tmp[p++]=v[j++];
        for(int k=l;k<=mid;k++) add(v[k].c,-v[k].cnt); 
        for(int k=l;k<=r;k++) v[k]=tmp[k];
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&w[i].a,&w[i].b,&w[i].c);
            w[i].id=i;
        }
        sort(w+1,w+n+1,cmp);
        int tot=0;
        for(int i=1;i<=n;i++){ 
            if(w[i].a!=w[i-1].a||w[i].b!=w[i-1].b||w[i].c!=w[i-1].c)
                v[++tot]=w[i];
            v[tot].cnt++;
        }
        //cout<<endl;
        //for(int i=1;i<=tot;i++) printf("%d %d %d %d %d\n",v[i].a,v[i].b,v[i].c,v[i].id,v[i].cnt);
        CDQ(1,tot);
        for(int i=1;i<=tot;i++){
            //cout<<i<<" "<<num[v[i].id]<<endl;
            ans[num[v[i].id]+v[i].cnt-1]+=v[i].cnt;
        }
        for(int i=0;i<n;i++){
            printf("%d\n",ans[i]);
        }
    }
以陌上花开为例

莫队

        for(register int i=1;i<=m;i++){
            while(l<q[i].l) chg(l++,-1);
            while(l>q[i].l) chg(--l,1);
            while(r>q[i].r) chg(r--,-1);
            while(r<q[i].r) chg(++r,1);
            ans[q[i].id]=a[1].sum;
        }
莫队大概结构
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m;
    long long a[51000],b[51000],c[51000],tmp[51000];
    struct node{
        int l,r,id;
        long long x,y;
    }q[51000];
    long long cmp(node a,node b){
        return a.l==b.l?a.r<b.r:a.l<b.l;
    }
    long long gcd(long long a,long long b){
        return b?gcd(b,a%b):a;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
        for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
        sort(q+1,q+m+1,cmp);
        int l=1,r=1;
        tmp[c[1]]++;
        long long res=1;
        for(int i=1;i<=m;i++){
            while(l<q[i].l) res=res-tmp[c[l]]*2+1,tmp[c[l++]]--;
            while(l>q[i].l) res=res+tmp[c[--l]]*2+1,tmp[c[l]]++;
            while(r>q[i].r) res=res-tmp[c[r]]*2+1,tmp[c[r--]]--;
            while(r<q[i].r) res=res+tmp[c[++r]]*2+1,tmp[c[r]]++;
            q[i].x=res-(r-l+1);
            q[i].y=(long long)(r-l+1)*(r-l);
            if(q[i].x==0) a[q[i].id]=0,b[q[i].id]=1;
            else{
                long long g=gcd(q[i].x,q[i].y);
                a[q[i].id]=q[i].x/g,b[q[i].id]=q[i].y/g;
            } 
        }
        for(int i=1;i<=m;i++)
            printf("%lld/%lld\n",a[i],b[i]);
    }
以小z的袜子为例

BSGS(比较好理解而且短的板子,附上Lockey的详细说明~)

long long pow(long long a,long long b,long long mod){
    long long ans=1;
    a%=mod;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans%mod;
}
//求 A^x同余Bzai在模p意义下
// 设m=sqrt(p),x=i*m-j
//则 A^(i*m-j) %p=B
// A^(i*m) %p= B*A^j %p
//预处理 B*A^j%p 用hash存起来(可以用map,hash[B*A^j%p]=j),
//枚举 i 计算 A^(i*m) 如果存在 A^(i*m)%p=B*A^j%p ,则hash[A^(i*m)%p]=j
//最终ans=i*m-j;
long long BSGS(long long y,long long z,long long p){
//开头加点儿特判啥的都可以
    hs.clear();//千万不要用hash这个名字,会CE
    long long m=ceil(sqrt(p*1.0)),s=z%p,t;
    hs[s]=0;
    for(int i=1;i<=m;i++){
        s=s*y%p;
        hs[s]=i;//将 B*A^j%p 存进hash表
    }
    t=pow(y,m,p),s=1;
    for(int i=1;i<=m;i++){
        s=s*t%p;
        if(hs[s]){//找到符合条件的j
            ans=i*m-hs[s];//得出答案
            return ans;
        }
    }
    return -1;
}
BSGS(map版)
    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<cmath>
    using namespace std;
    long long T,p,a,b,x1,t;
    map<long long,int>hs;
    long long pow(long long a,long long b,long long p){
        long long ans=1;
        a%=p;
        while(b){
            if(b&1) ans=ans*a%p;
            b>>=1;
            a=a*a%p;
        }
        return ans%p;
    }
    void BSGS(long long a,long long b,long long p){
        hs.clear();     
      //  a%=p,b%=p;   
        long long  m=ceil(sqrt(p*1.0)),s=b%p,t;
        hs[s]=0;
        for(int i=1;i<=m;i++) s=s*a%p,hs[s]=i;
        t=pow(a,m,p),s=1;
        for(int i=1;i<=m;i++){
            s=s*t%p;
            if(hs[s]){
                printf("%lld\n",i*m-hs[s]+1);
                return;
            }
        }
        printf("-1\n");
        return;
    }
    int main(){
        scanf("%lld",&T);
        while(T--){
            scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
            b%=p;
            a%=p;
            if(x1==t) printf("1\n");
            else if(a==0&&t==b) printf("2\n");
            else if(a==0&&t!=b) printf("-1\n");
            else if(a==1){
                if(b==0) printf("-1\n");
                else  printf("%lld\n",(t-x1+p)%p*pow(b,p-2,p)%p+1);   
            }
            else{
                int B=(((t-b*pow(1-a,p-2,p))+p)%p*pow(x1-b*pow(1-a,p-2,p),p-2,p)+p)%p;
                BSGS(a,B,p);
            }
        }
    }
以随机数生成器为例

 dijistra(堆优化)板子

long long dis[11000],v[11000];
struct node{
    int to,len;
};
struct haha{
    long long x,d;
    haha(long long a,long long b){x=a,d=b;}
};
struct cmp{
    bool operator () (haha &a,haha &b){
        return a.d>b.d;
    }
};
vector<node>son[11000];
long long min(long long a,long long b){
    return a<b?a:b;
}
void dijkstra(int w){
    priority_queue<haha,vector<haha>,cmp>q;
    dis[1]=0;
    q.push(haha(1,0));
    while(!q.empty()){
        int x=q.top().x;
        q.pop();
        v[x]=1;
        for(int k=0;k<son[x].size();k++){
            if(x==1&&k==w) continue;
            int y=son[x][k].to,len=son[x][k].len;
            if(!v[y]&&dis[y]>dis[x]+len){
                dis[y]=dis[x]+len;
                q.push(haha(y,dis[y]));
            }
        }
    }
}
View Code

高精乘除低精

void multi(int x){//高精乘低精
    int tmp=0;
    for(int i=1;i<=ans[0];i++){
        tmp=ans[i]*x+tmp;
        ans[i]=tmp%10;
        tmp=tmp/10;
    }
    while(tmp) ans[++ans[0]]=tmp%10,tmp/=10;
}
void div(int x){//高精除低精
    int tmp=0;
    for(int i=ans[0];i>=1;i--){
        tmp+=ans[i];
        ans[i]=tmp/x;
        tmp%=x;
        tmp*=10;
    }
    while(ans[ans[0]]==0&&ans[0]>1) ans[0]--;
}
View Code

欧拉函数值求解

欧拉函数用希腊字母φ表示,φ(N)表示N的欧拉函数.

对φ(N)的值,我们可以通俗地理解为小于N且与N互质的数的个数(包含1).

欧拉函数的一些性质:

1.对于素数p, φ(p)=p-1,对于对两个素数p,q φ(pq)=pq-1

欧拉函数是积性函数,但不是完全积性函数.

2.对于一个正整数N的素数幂分解N=P1^q1*P2^q2*...*Pn^qn.

   φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).

3.除了N=2,φ(N)都是偶数.

4.设N为正整数,∑φ(d)=N (d|N).
关于欧拉函数的一些知识(性质)
int euler(int x){
    int phi=x;
    for(int i=2;i<=x;i++){
        if(x%i==0){
            phi/=i*(i-1);
            while(x%i==0) x/=i;
        }
    }
    if(x>1) phi/=x*(x-1);
    return phi;
}
求解单个数的phi值

 

1 phi[1]=1;
2 for(register int i=2;i<=10000000;i++){
3     if(!phi[i]) phi[i]=i-1,prm[++prm[0]]=i;
4     for(register int j=1;j<=prm[0]&&i*prm[j]<=10000000;j++){
5         if(i%prm[j]==0){phi[i*prm[j]]=phi[i]*prm[j];break;}
6         else phi[i*prm[j]]=phi[i]*(prm[j]-1);
7     }
8 }
欧拉函数线性筛

 

组合数取模7种类型(尤其是模数为非质数)(重点)

类型0:n,m<=1000 直接暴力预处理杨辉三角,预处理复杂度O(n*n) 公式:C(n,m)=C(n,n-m)=C(n-1,m-1)+C(n-1,m)

类型1:n,m<=1e6   且模数p是质数。   O(n)预处理 阶乘fac[i]和阶乘的逆ifac即可。然后 C(n,m)=fac[n]*ifac[m]*ifac[n-m]

预处理复杂度O(n),查询O(1)。HDU6333 Problem B. Harvest of Apples 莫队算法+逆元

类型2:n,m <=1e18 且模数p为质数,且p<=1e5,用Lucas定理,展开成多个组合数的乘积。

单次查询复杂度O(p*log(n)/log(p))  HDU3037 Saving Beans Lucas 定理+逆元

类型3:n,m,p <=1e18 且模数p为非质数,用Lucas定理+中国剩余定理

单次查询复杂度O(VY*p*log(n)/lop(p))V,Y为p的质因子个数和幂次 HDU5446 Unknown Treasur Lucas+中国剩余定理

类型4:n<=1e9,m<=1e5, p<=1e9且为质数,用逆元暴力计算C(n,m)=n*(n-1)*(n-2)*……*(n-m+1)/(1*2*……*m)

算法复杂度O(m)

类型5: n,m<=1e5,mod非质数, 对阶乘分解质因数,然后跑快速幂,算法复杂度O(n)
组合数取模6种类型
for(int i=2;i<=n*2;i++){
        if(!vis[i]) prim[++prim[0]]=i;
        for(int j=1;j<=prim[0]&&i*prim[j]<=n*2;j++){
            vis[i*prim[j]]=1;
            if(i%prim[j]==0) break;
        }
    }
    for(int i=1;i<=prim[0];i++){
        for(int j=n*2;j/=prim[i];) a[i]+=j; 
        for(int j=n;j/=prim[i];) a[i]-=j;
        for(int j=n+1;j/=prim[i];) a[i]-=j;
        ans=(ans*pow(prim[i],a[i]))%mod;
    }
模数为非质数的阶乘质因数分解法

 可以看一下这篇博客 证明时间复杂度为O(n) 可以看Yu_shi的博客

long long china(){
    long long ans=0;
    for(int i=1;i<=prm[0];i++){
        long long a=mod/prm[i];
        exgcd(a,prm[i]);
        ans=(ans+a*x*b[i]%mod)%mod;
    }
    if(ans>=0)
        return ans;
    else 
        return ans%mod+mod;
}
CRT(中国剩余定理)

详解请点击这里 密码为机房帐号+密码

long long pow(long long a,long long b,long long p){
    long long ans=1;
    a%=p;
    while(b){
        if(b&1) ans=ans*a%p;
        b>>=1;
        a=a*a%p;
    }
    return ans%p;
}
long long C(int n,int m,int p){
    if(n<m) return 0;
    else return fac[n]%p*pow(fac[n-m]*fac[m]%p,p-2,p)%p;
}
long long lucas(int a,int b,int p){
    if(!b) return 1;
    else return lucas(a/p,b/p,p)%p*C(a%p,b%p,p)%p; 
}
Lucas定理求组合数

 

prufer序列

证明n个点生成n^(n-2)个无根树参照博客这篇

高斯消元

 1 void gauss(){
 2         for(int i=1;i<=n;i++){
 3         int p=i;
 4         for(int j=i+1;j<=n;j++) 
 5             if(fabs(a[j][i])>fabs(a[p][i])) p=j;
 6         for(int j=1;j<=n+1;j++) swap(a[i][j],a[p][j]);
 7         if(fabs(a[i][i])<eps) continue;
 8         double tem=a[i][i];
 9         for(int j=1;j<=n+1;j++) a[i][j]/=tem;
10         for(int j=1;j<=n;j++)
11             if(i!=j){
12                 tem=a[j][i];
13                 for(int k=1;k<=n+1;k++) a[j][k]-=a[i][k]*tem;
14             }
15     }
16 }
View Code

分治消元(消后一半求前一半,还原后小前一半求后一半)

 1 struct node{
 2     int a[310][310];
 3 }st[15];
 4 int a[310][310],ans[310];
 5 void gouss(int i,int l,int r){
 6     long long tmp=qpow(a[i][i],mod-2);
 7     for(register int j=1;j<=n+1;j++) a[i][j]=tmp*a[i][j]%mod;
 8     for(register int j=1;j<=n;j++){
 9         if(i==j) continue;
10         tmp=a[j][i];
11         for(register int k=l;k<=r;k++){
12             a[j][k]=(a[j][k]-tmp*a[i][k])%mod;
13         }
14         a[j][n+1]=(a[j][n+1]-tmp*a[i][n+1])%mod;
15     }
16 }
17 void solve(int l,int r){
18     if(l==r){
19         ans[l]=a[1][n+1];
20         return;
21     }
22     top++;
23     for(register int i=1;i<=n;i++){
24         for(register int j=1;j<=n+1;j++){
25             st[top].a[i][j]=a[i][j];
26         }
27     }
28     int mid=(l+r)>>1;
29     for(register int i=mid+1;i<=r;i++)     gouss(i,l,r);
30     solve(l,mid);
31     for(register int i=1;i<=n;i++){
32         for(register int j=1;j<=n+1;j++){
33             a[i][j]=st[top].a[i][j];
34         }
35     }
36     for(register int i=l;i<=mid;i++) gouss(i,l,r);
37     solve(mid+1,r);
38     top--;
39 }
以CSP-S模拟93的第三题 走路 为例 的整数高斯消元

 

posted @ 2019-07-19 07:09  Lockey_T  阅读(392)  评论(3编辑  收藏  举报