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

KD-Tree

#include
#include
#include
#include
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]1]?0:1;
    if(Dis[first]ch[first],cmp);
    if(Dis[first^1]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
    #include
    #include
    #include
    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>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//小根堆
        if(to1].val>h[to].val) ++to; //大根堆
    //    if(h[to].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<
            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
    #include
    #include
    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.cy.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<
            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<
        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<//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<
            ans[num[v[i].id]+v[i].cnt-1]+=v[i].cnt;
        }
        for(int i=0;i){
            printf("%d\n",ans[i]);
        }
    }
以陌上花开为例

莫队

        for(register int i=1;i<=m;i++){
            while(l1);
            while(l>q[i].l) chg(--l,1);
            while(r>q[i].r) chg(r--,-1);
            while(r1);
            ans[q[i].id]=a[1].sum;
        }
莫队大概结构
    #include
    #include
    #include
    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.rb.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(l2+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(r2+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
    #include
    #include
    #include
    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;
    }
};
vectorson[11000];
long long min(long long a,long long b){
    return aa:b;
}
void dijkstra(int w){
    priority_queue,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){
            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(nreturn 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)个无根树参照博客这篇

高斯消元

void gauss(){
        for(int i=1;i<=n;i++){
        int p=i;
        for(int j=i+1;j<=n;j++) 
            if(fabs(a[j][i])>fabs(a[p][i])) p=j;
        for(int j=1;j<=n+1;j++) swap(a[i][j],a[p][j]);
        if(fabs(a[i][i])continue;
        double tem=a[i][i];
        for(int j=1;j<=n+1;j++) a[i][j]/=tem;
        for(int j=1;j<=n;j++)
            if(i!=j){
                tem=a[j][i];
                for(int k=1;k<=n+1;k++) a[j][k]-=a[i][k]*tem;
            }
    }
}
View Code

你可能感兴趣的:(一些理解加记住的板子们(知识理解))