zoukankan      html  css  js  c++  java
  • 一些理解加记住的板子们(知识理解)

    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;        
        }
    }

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

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

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

    平方和公式

      $largesumlimits_{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
    ",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
    ");
                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
    ",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
    ",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
    ",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
    ",i*m-hs[s]+1);
                    return;
                }
            }
            printf("-1
    ");
            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
    ");
                else if(a==0&&t==b) printf("2
    ");
                else if(a==0&&t!=b) printf("-1
    ");
                else if(a==1){
                    if(b==0) printf("-1
    ");
                    else  printf("%lld
    ",(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的第三题 走路 为例 的整数高斯消元
  • 相关阅读:
    [LC] 270. Closest Binary Search Tree Value
    [LC] 452. Minimum Number of Arrows to Burst Balloons
    [LC] 494. Target Sum
    [LC] 350. Intersection of Two Arrays II
    [LC] 349. Intersection of Two Arrays
    [LC] 322. Coin Change
    scala--函数和闭包
    scala-- 内建控制结构
    scala--函数式对象
    scala --操作符和运算
  • 原文地址:https://www.cnblogs.com/heoitys/p/11211033.html
Copyright © 2011-2022 走看看