模板集

 oi各类模板集

https://www.luogu.org/paste/h3mzcfo1

https://www.cnblogs.com/phemiku/p/11622062.html

 

各种模板题

 

1.快速幂与快速乘

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int kase, a, b, q;
ll c, d, r;

int qpow(int a, int b, int q) {
    ll s = 1;
    while (b) {
        if (b & 1)
            s = s * a % q;
        a = (ll)a * a % q;
        b >>= 1;
    }
    return s;
}

ll qmul(ll c, ll d, ll r) {
    ll s = 0;
    while (d) {
        if (d & 1)
            s = (s + c) % r;
        c = (c + c) % r;
        d >>= 1;
    }
    return s;
}

int main() {
    scanf("%d", &kase);
    while (kase--) {
        scanf("%d%d%d%lld%lld%lld", &a, &b, &q, &c, &d, &r);
        printf("%d %lld\n", qpow(a, b, q), qmul(c, d, r));
    }
}

2.归并排序

//划分问题:把序列分成元素个数尽量相等的两半
//递归求解:把两半元素分别排序
//合并问题:把两个有序表合并为一个
//如果左边最小的数都比右边这个数大,
//那么左边剩余的所有数都会比右边这个数大
#include <bits/stdc++.h>
using namespace std;

#define N 1000005
int n, a[N], b[N];
long long cnt;

void merge_sort(int l, int r) {
    if (l < r) {
        int mid = (l + r) / 2;
        int i = l;
        int p = l, q = mid + 1;
        merge_sort(l, mid);
        merge_sort(mid + 1, r);
        while (p <= mid || q <= r)
            if (q > r || (p <= mid && a[p] <= a[q]))
                b[i++] = a[p++];
            else {
                b[i++] = a[q++];
                cnt += mid - p + 1;  //将逆序对的个数累加起来
            }
        for (i = l; i <= r; i++) a[i] = b[i];
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    merge_sort(1, n);
    printf("%lld", cnt);
}

3.ST表

#include <bits/stdc++.h>
using namespace std;

const int N = 500009;
int m, Log[N];

struct ST {
    int st[21][N], n;
    int query(int l, int r) {
        assert(l <= r && r <= n);
        int t = Log[r - l + 1];
        return min(st[t][l], st[t][r - (1 << t) + 1]);
    }
    void push_back(int x) {
        st[0][++n] = x;
        for (int i = 1;; i++) {
            int l = n - (1 << i) + 1;
            if (l >= 1) {
                st[i][l] = min(st[i - 1][l], st[i - 1][l + (1 << (i - 1))]);
            } else
                break;
        }
    }
    void pop_back() { n--; }
} st;

int main() {
    scanf("%d", &m);
    for (int i = 2; i < N; i++) {
        Log[i] = Log[i >> 1] + 1;
    }

    while (m--) {
        char opt[9];
        scanf("%s", opt);
        if (opt[0] == 'I') {
            int x;
            scanf("%d", &x);
            st.push_back(x);
        } else if (opt[0] == 'Q') {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d\n", st.query(l, r));
        } else {
            st.pop_back();
        }
    }
    return 0;
}

4.左偏树

// ①:空节点为-1(性质推得)
// ②:删除操作:将其左右子树合并,接上去即可
//     插入操作:将插入的点用倍增合成一树,插入即可
//     替换操作:先删除再插入(注意删除时d[x]=r[x]=v[x]=l[x]=0)
#include<bits/stdc++.h>
#define Int register int
#define N 100005
using namespace std;

int n,m;
int fa[N],son[N][2],dead[N],dist[N],val[N];

int read (int &x){
    x = 0;
    char c = getchar();
    int f = 1;
    while(c < '0' || c > '9') {if (c == '-') f = -f;c = getchar();}
    while(c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + c - '0';c = getchar();}
    return x*f; 
}

void write (int x){
    if(x < 0) {x = -x;putchar ('-');}
    if(x > 9) write (x / 10);
    putchar (x % 10 + '0'); 
} 

int findSet (int x){
    if (x != fa[x])
        fa[x] = findSet (fa[x]);
    return fa[x];
}

int Merge (int x,int y){
    if (!x || !y) 
        return x | y;
    //if(x==0)   return y;   //只剩某一子数(点)的情况 
    //if(y==0)   return x;
    //判断到尽头,儿子为空要返回对应的另一结点    
    if (val[x] > val[y] ) 
        swap (x,y);
    //如果值x大于y 或者值相同情况下 x的位置在y右边 交换
    son[x][1] = Merge (son[x][1],y);
    //将y不断地和x的右儿子进行合并
    //将合并后的新的右儿子的父亲边连上
    dist[x] = dist[son[x][1]] + 1;
    //fa[lson[x]]=fa[rson[x]]=fa[x]=x;
    //如果右儿子的dis要大于左儿子 进行交换
    //dis[x]=(rson[x]==0?0:dis[rson[x]]+1);
    //x的dis为其右儿子的dis+1
    //若无右儿子则dis为0
    if (dist[x] > dist[son[x][0]] + 1) 
        swap (son[x][0],son[x][1]);
    fa[son[x][0]] = fa[son[x][1]] = fa[x] = x;
    return x;
}

int Ask (int x){
    dead[x] = 1;
    int tmp = val[x];
    fa[son[x][0]] = son[x][0];
    fa[son[x][1]] = son[x][1];
    fa[x] = Merge (son[x][0],son[x][1]);
    return tmp;
}

signed main(){
    read(n),read(m);
    for (Int i = 1;i <= n;++ i) 
        fa[i] = i,read (val[i]);
    for (Int i = 1;i <= m;++ i) {
        int opt;
        read (opt);
        if(opt == 1){
            int x,y;
            read (x),read (y);
            if (dead[x] || dead[y]) continue;
            x = findSet (x),y = findSet (y);
            if (x != y)
                fa[x] = fa[y] = Merge (x,y);
        } else if(opt == 2){
            int x;
            read (x);
            if(dead[x]) puts ("-1");
            else write (Ask (findSet (x))),putchar ('\n'); 
        }
    }
}

5.最短路

(1)SPFA

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 9;
int n, m, mod;

struct Edge {
    int v, w;
    Edge *nxt;
    bool ok;
} e[N<<1];
int e_cnt;
Edge *head[N];
void addEdge(int u, int v, int w) {
    e[++e_cnt] =(Edge){ v, w, head[u], false };
    head[u] = &e[e_cnt];
}

int dis[N];
bool inq[N];
queue<int> q;
void SPFA() {
    q.push(1);
    dis[1] = 0;
    inq[1] = true;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (Edge *i = head[u]; i != NULL; i = i->nxt) {
            int v = i->v, w = i->w;
            if (dis[v] > dis[u] + w ) {
                dis[v] = dis[u] + w;
                if (!inq[v]) {
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
        inq[u] = false;
    }
}

int ind[N], f[N];
void dp() {
    f[1] = 1;
    q.push(1);
    inq[1] = true;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (Edge *i = head[u]; i != NULL; i = i->nxt) {
            int v = i->v, w = i->w;
            if (dis[v] == dis[u] + w) {
                i->ok = true;
                ++ind[v];
                if (!inq[v]) {
                    q.push(v);
                    inq[v] = true;
                }
            }
        }
    }
    q.push(1);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (Edge *i = head[u]; i != NULL; i = i->nxt) {
            if (!(i->ok)) continue;
            int v = i->v, w = i->w;
            f[v] = (f[v] + f[u]) % mod;
            if (--ind[v] == 0)
                q.push(v);
        }
    }
}

int main() {
    int kase;
    scanf("%d", &kase);
    while (kase--) {
        scanf("%d%d%d", &n, &m, &mod);
        e_cnt = 0;
        for (int i = 1; i <= n; ++i) {
            head[i] = NULL;
            dis[i] = 1e9;
            f[i] = 0;
            ind[i] = 0;
            inq[i] = false;
        }
        for (int i = 0, x, y, z; i < m; ++i) {
            scanf("%d%d%d", &x, &y, &z);
            addEdge(x, y, z);
        }
        SPFA();
        dp();
        for (int i = 2; i <= n; ++i) 
            printf("%d ", f[i]);
        puts("");
    }
}

(2)Dijkstra

#include<bits/stdc++.h>
using namespace std;

const int N=1e7+10;
int n,m,head[N],tot;
int dis[N],t,rxa,rxc,rya,ryc,rp;

struct node{
    int to,nxt,w;
}e[N]; 
bool inq[N];
priority_queue<pair<int ,int > >q;

int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x*10+ch-'0');
        ch=getchar();
    }
    return x*f;
}

void add(int u,int v,int w){
    e[++tot].to=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
}

int main(){
    n=read(),m=read(),t=read();
    rxa=read(),rxc=read(),rya=read(),ryc=read();
    rp=read();
    int x=rxc%rp,y=ryc%rp;
    int a = min(x%n+1,y%n+1) , b=y%n+1;
    add(a,b,1e8-100*a);
    for(int i=1;i<=m-t;i++){
        int xx,yy,zz;
        xx=read(),yy=read(),zz=read();
        add(xx,yy,zz);
    } 
    
    memset(dis,0x3f,sizeof dis);
    dis[1]=0;
    q.push(make_pair(0,1));
    inq[1]=0;
    while(!q.empty()){
        int x=q.top().second;
        q.pop();
        if(inq[x]) continue;
        inq[x]=1;
        for(int i=head[x];i;i=e[i].nxt){
            int to=e[i].to,w=e[i].w;
            if(dis[to]>dis[x]+w){
                dis[to]=dis[x]+w;
                q.push(make_pair(-dis[to],to));
            }
        }
    }
    printf("%d",dis[n]);
}

(3) BFS 

最短路计数(求1到其他顶点的最短路条数)

 

( 边权为1时 )

#include<bits/stdc++.h>
using namespace std;

const int N=1e6+5,M=4e6+5;
int mod=1e5+3;
int n,m,x,y,tot;
int head[N],to[N],nxt[M],d[N],ans[N];
bool p[N];
queue<int>q;

void add(int x,int y){
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
} 

int main(){
    scanf("%d%d",&n,&m);
    while(m){
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
        m--;
    }
    for(int i=1;i<=n;i++){
        d[i]=1e9;
        p[i]=0; 
    }
    d[1]=0;
    p[1]=1;
    ans[1]=1;
    q.push(1);
    while(q.size()){
        x=q.front();
        q.pop();
        p[x]=0;
        for(int i=head[x];i;i=nxt[i]){
            y=to[i];
            if(d[y]>d[x]+1){
                d[y]=d[x]+1;
                ans[y]=ans[x];
                if(!p[y]){
                    q.push(y);
                    p[y]=1;
                }
            }
            else if(d[y]==d[x]+1){
                ans[y]+=ans[x];
                ans[y]%=mod;
            }
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);
}

6.MST(最小生成树)

(1)洛谷模板题

#include <bits/stdc++.h>
using namespace std;
const int N = 400015;

struct edge {
    int u,v,w;
} edges[N];
int n, m, cnt, tot,fa[N];
long long ans;

bool cmp(edge x, edge y) { return x.w < y.w; }

int find(int x) {
    if(x == fa[x]) return x;
    else return fa[x] = find(fa[x]);
}

bool merge(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return 0;
    fa[x] = y;
    return 1;//??
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int x, y, p;
        scanf("%d%d%d", &x, &y, &p);
        edges[++tot] = (edge){ x, y, p };
    }
    sort(edges + 1, edges + 1 + tot, cmp);
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 1; i <= tot; i++) {
        int u = edges[i].u;
        int v = edges[i].v;
        if (merge(u, v)) {
            ans += edges[i].w;
            cnt++;
        }
        if (cnt == n - 1) break;
    }
    if (cnt != n - 1) printf("orz"); //什么鬼输出
    else printf("%lld", ans);
}

(2)

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;

struct Edge {
    int to, w;
};
vector<Edge> G[N];

int n, m, done[N];

struct Node {
    int d, v;
    bool operator<(const Node &rhs) const { return d > rhs.d; }
};
priority_queue<Node> q;

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].push_back((Edge){ v, w });
        G[v].push_back((Edge){ u, w });
    }

    q.push((Node){ 0, 1 });
    long long ans = 0;
    for (int i = 1; i <= n; i++) {
        Node u;
        do {
            if (!q.size()) {
                puts("-1");
                return 0;
            }
            u = q.top();
            q.pop();
        } while (done[u.v]);
        ans += u.d;
        done[u.v] = 1;
        for (unsigned i = 0; i < G[u.v].size(); i++) {
            Edge &e = G[u.v][i];
            q.push((Node){ e.w, e.to });
        }
    }
    cout << ans << endl;
}

7.线段树

//线段树 
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N=2e5+9; 
int n,m;
ll sum[N<<2]/*4倍空间*/,tag[N<<2];

void pushup(int u){
    sum[u]=sum[u<<1]+sum[u<<1|1];
}

void buildtree(int u,int ul,int ur){
    if(ul==ur){//如果是叶节点 
        scanf("%ll",sum+u);
        return;
    }
    int mid=ul+ur>>1;
    buildtree(u<<1,ul,mid);
    buildtree(u<<1|1,mid+1,ur);
    pushup(u);
}

void update(int u,int ul,int ur,int mx){
    tag[u]+=mx;
    sum[u]+=(ll)mx*(ur-ul+1);
}

void pushdown(int u,int ul,int ur){
    if(tag[u]){
        int mid=ul+ur>>1;
        update(u<<1,ul,mid,tag[u]);
        update(u<<1|1,mid+1,ur,tag[u]);
        tag[u]=0;
    }
}

void modify(int u,int ul,int ur,int ml,int mr,int mx){
    if(ml<=ul&&ur<=mr){
        update(u,ul,ur,mx);
        return;
    }
    pushdown(u,ul,ur);
    int mid=ul+ur>>1;
    if(ml<=mid)
        modify(u<<1,ul,mid,ml,mr,mx);
    if(mr>=mid+1)
        modify(u<<1|1,mid+1,ur,ml,mr,mx);
    pushup(u);
}

ll query(int u,int ul,int ur,int ml,int mr){
    if(ml<=ul&&ur<=mr)
        return sum[u];
    pushdown(u,ul,ur);
    int mid=ul+ur>>1;
    ll s=0;
    if(ml<=mid)
        s+=query(u<<1,ul,mid,ml,mr);
    if(mr>=mid+1)
        s+=query(u<<1|1,mid+1,ur,ml,mr);
    return s;
}

int main(){
    scanf("%d%d",&n,&m);
    buildtree(1,1,n);
    while(m--){
        int opt,x,y,z;
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0){
            scanf("%d",&z);
            modify(1,1,n,x,y,z);//修改函数 
        } else{
            printf("%ll\n",query(1,1,n,x,y));
        } 
    }
}

 

8.树状数组

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 200005;
int n, m;
ll a[N], d[N], id[N];

int lowbit(int x){ return x&(-x); }
//算出x二进制的从右往左出现第一个1以及这个1之后的那些0组成数的二进制对应的十进制的数
//就是看区间和包括的数的个数 
//-x代表x的负数,用对应的正数的补码来表示。

void modify(ll *t, int i, ll x) {
    while (i <= n) { //不能越界 
        t[i] += x;
        i += lowbit(i);
    }
}

ll query(ll *t, int i) { //a[1]……a[x]的和 
    ll sum = 0;
    while (i) {
        sum += t[i];
        i -= lowbit(i);
    }
    return sum;
}

ll q(int r) { return query(d, r) * (r + 1) - query(id, r); }

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        modify(d, i, a[i] - a[i - 1]);
        modify(id, i, i * (a[i] - a[i - 1]));
    }
    while (m--) {
        ll opt, x, y, z;
        scanf("%lld%lld%lld", &opt, &x, &y);
        if (opt == 0) {
            scanf("%lld", &z);
            modify(d, x, z);
            modify(id, x, x * z);
            modify(d, y + 1, -z);
            modify(id, y + 1, (y + 1) * (-z));
        } else
            printf("%lld\n", (q(y) - q(x - 1)));
    }
    return 0;
}

 

9.拓扑序

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;

int n,m,du[N],f[N],cnt;
stack<int>s;

struct Edge{
    int next,to;
}edge[N<<1];
int tot,head[N];
void add(int from,int to){
    edge[++tot].next=head[from];
    edge[tot].to=to;
    head[from]=tot;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(v,u);
        du[u]++;
    }
    for(int i=1;i<=n;i++){
        f[i]=1;
        if(du[i]==0) s.push(i);
    }
    while(!s.empty()){
        int u=s.top();
        s.pop();
        ++cnt;
        for(int i=head[u];i;i=edge[i].next ){
            int v=edge[i].to;
            f[v]=max(f[v],f[u]+1);
            du[v]--;
            if(du[v]==0) s.push(v);
        }
    }
    if(cnt<n){
        printf("-1\n");
        return 0;
    }
    long long ans=0;
    for(int i=1;i<=n;i++) 
        ans+=f[i];
    printf("%lld",ans);
}

10.并查集

#include <bits/stdc++.h>
using namespace std;

const int N = 50000 + 10;
int fa[N], val[N];

int find(int x) {
    if (fa[x] == x)
        return x;
    int tmp = find(fa[x]);
    (val[x] += val[fa[x]]) %= 3;
    return fa[x] = tmp;
}

bool merge(int x, int y, int d) {
    int fx = find(x), fy = find(y);
    if (fx == fy)
        return (val[x] - val[y] - d) % 3 == 0 ? 1 : 0;
    fa[fy] = fx;
    val[fy] = (val[x] - val[y] - d + 6) % 3;
    return 1;
}

int main() {
    int n, k, ans = 0;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) fa[i] = i, val[i] = 0;
    while (k--) {
        int d, a, b;
        scanf("%d%d%d", &d, &a, &b);
        if (a > n || b > n || !merge(a, b, d - 1))
            ans++;
    }
    printf("%d\n", ans);

    return 0;
}

11.高精加减乘

 

#include <bits/stdc++.h>
using namespace std;
//compare比较函数:相等返回0,大于返回1,小于返回-1
int compare(string str1,string str2) {
    if(str1.length()>str2.length()) return 1;
    else if(str1.length()<str2.length()) return -1;
    else return str1.compare(str2);
}
//高精度加法
//只能是两个正数相加
string add(string str1,string str2) {
    string str;
    int len1=str1.length();
    int len2=str2.length();
    //前面补0,弄成长度相同
    if(len1<len2) {
        for(int i=1;i<=len2-len1;i++)
           str1="0"+str1;
    } else {
        for(int i=1;i<=len1-len2;i++)
           str2="0"+str2;
    }
    len1=str1.length();
    int cf=0, temp;
    for(int i=len1-1;i>=0;i--) {
        temp=str1[i]-'0'+str2[i]-'0'+cf;
        cf=temp/10;
        temp%=10;
        str=char(temp+'0')+str;
    }
    if(cf!=0)  
        str=char(cf+'0')+str;
    return str;
}
//高精度减法
//只能是两个正数相减,而且要大减小
string sub(string str1,string str2) {
    string str;
    int tmp=str1.length()-str2.length();
    int cf=0;
    for(int i=str2.length()-1;i>=0;i--) {
        if(str1[tmp+i]<str2[i]+cf) {
            str=char(str1[tmp+i]-str2[i]-cf+'0'+10)+str;
            cf=1;
        } else {
            str=char(str1[tmp+i]-str2[i]-cf+'0')+str;
            cf=0;
        }
    }
    for(int i=tmp-1;i>=0;i--) {
        if(str1[i]-cf>='0') {
            str=char(str1[i]-cf)+str;
            cf=0;
        } else {
            str=char(str1[i]-cf+10)+str;
            cf=1;
        }
    }
    str.erase(0,str.find_first_not_of('0'));//去除结果中多余的前导0
    return str;
}
//高精度乘法
//只能是两个正数相乘
string mul(string str1,string str2) {
    string str;
    int len1=str1.length();
    int len2=str2.length();
    string tem;
    for(int i=len2-1;i>=0;i--) {
        tem ="";
        int temp=str2[i]-'0';
        int t=0, cf=0;
        if(temp!=0)  {
            for(int j=1;j<=len2-1-i;j++)
              tem +="0";
            for(int j=len1-1;j>=0;j--) {
                t=(temp*(str1[j]-'0')+cf)%10;
                cf=(temp*(str1[j]-'0')+cf)/10;
                tem =char(t+'0')+tem;
            }
            if(cf!=0) tem =char(cf+'0')+tem;
        }
        str=add(str,tem);
    }
    str.erase(0,str.find_first_not_of('0'));
    return str;
}
//高精度除法
//两个正数相除,商为quotient,余数为residue
//需要高精度减法和乘法
void div(string str1,string str2,string &quo,string &resi) {
    quo =resi ="";//清空
    if(str2=="0") {//判断除数是否为0
        quo =resi ="ERROR";
        return;
    }
    if(str1=="0") {//判断被除数是否为0
        quo =resi ="0";
        return;
    }
    int res=compare(str1,str2);
    if(res<0) {
        quo ="0";
        resi =str1;
        return;
    } else if(res==0) {
        quo ="1";
        resi ="0";
        return;
    } else {
        int len1=str1.length();
        int len2=str2.length();
        string tem ;
        tem .append(str1,0,len2-1);
        for(int i=len2-1;i<len1;i++) {
            tem =tem +str1[i];
            tem .erase(0,tem .find_first_not_of('0'));
            if(tem .empty())
                  tem ="0";
            for(char ch='9';ch>='0';ch--) {//试商
                string str,tmp;
                str=str+ch;
                tmp=mul(str2,str);
                if(compare(tmp,tem )<=0) {//试商成功
                    quo =quo +ch;
                    tem =sub(tem ,tmp);
                    break;
                }
            }
        }
        resi =tem ;
    }
    quo .erase(0,quo .find_first_not_of('0'));
    if(quo .empty()) 
        quo ="0";
}

int main() {
    string a, b, c, d;
    cin >> a >> b;
    div(a, b, c, d);
    cout << c;
} 

 

12.压位+floyd

#include <bits/stdc++.h>
using namespace std;

const int N = 2005;
int f[N][N], n;

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        char a[N];
        scanf("%s", &a);
        a[i] = '1';  //对角线上的
        for (int j = 0; j < n; j++)
            if (a[j] - '0' == 1) {
                int k = j % 32;
                f[i][j / 32] |= 1 << k;  // 1左移k位,加入集合
            }
    }
    for (int k = 0; k < n; k++) {
        for (int i = 0; i < n; i++) {
            if (i == k)
                continue;
            if (!(f[i][k / 32] & 1 << (k % 32)))  // i能到达k
                continue;
            for (int j = 0; j <= n / 32; j++) f[i][j] = f[k][j] | f[i][j];  //从k能到j的并上从i到j的
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j <= n / 32; j++)
            for (int k = 0; k <= 31 && j * 32 + k < n; k++)  //遍历k位
                putchar(((f[i][j] >> k) & 1) + '0');         //看每一位能否到达
        printf("\n");                                        // puts("");换行
    }
}

13.Lucas

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 200005;
ll a[N];
int p;

int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0') {
        if (ch == '-') f= -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * f;
}

ll pow(ll a, ll b, ll mod) {
    ll ans = 1;
    while (b) {
        if (b & 1)
            ans = ans * a % mod;
        b >>= 1;
        a = a * a % mod; 
    }
    return ans;
}

ll C(ll n, ll m) {//求阶乘
    ll ans = 1;
    for (int i = n - m + 1; i <= n; i++)
        ans = ans * i % p;
    return ans;
}

ll Lucas(ll n, ll m) { //卢卡斯定理
    if (!m) return 1;
    if (n < p && m < p)
        return C(n, m) * pow(a[m], p - 2, p) % p;
    return Lucas(n % p, m% p) * Lucas(n / p, m / p) % p;
}

int main() {
    int T = read();
    while (T--) {
        int n = read(), m = read();
        p = read();
        a[0] = 1;
        for (int i = 1; i <= m; i++)
            a[i] = (a[i - 1] * i) % p; //预处理阶乘到m
        cout << Lucas(n, m) << endl;
    }
}

 

14.LCA

#include <bits/stdc++.h>
using namespace std;

const int N = 20050;
vector<int> to[N];
int n,m,f[N][20], d[N], bu[N][N], cnt[N], ans[N], fa[N];

void insert(int u, int v) { 
    to[u].push_back(v); 
}

void dfs(int u, int h) {
    for (unsigned int i = 0; i < to[u].size(); i++) {
        int v = to[u][i];
        if (v != fa[u]) {
            d[v] = h;
            cnt[v] = cnt[u] + bu[v][u];
            fa[v] = u;
            dfs(v, h + 1);
        }
    }
}

void init() {
    for (int i = 1; i <= n; i++)
        f[i][0] = fa[i];
    for (int j = 1; j <= 19; j++)
        for (int i = 1; i <= n; i++)
            f[i][j] = f[f[i][j - 1]][j - 1];
}

int lca(int u, int v) {
    if (d[u] != d[v]) {
        if (d[u] > d[v])
            swap(u, v);
        int x = d[v] - d[u], j = 0;
        while (x) {
            if (x & 1)
                v = f[v][j];
            x >>= 1;
            j++;
        }
    }
    if (u == v)
        return u;
    for (int i = 19; i >= 0; i--) {
        if (f[u][i] != f[v][i]) {
            u = f[u][i];
            v = f[v][i];
        }
    }
    return fa[u];
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 1; i < n; i++) {
        int b, c, t;
        scanf("%d%d%d",&b,&c,&t);
        insert(c, b);
        insert(b, c);
        bu[b][c] = t;
        bu[c][b] = t;
    }

    d[1] = 1;
    dfs(1, 2);

    init();
    for (int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d%d",&x,&y);
        ans[i] = cnt[x] + cnt[y] - 2 * cnt[lca(x, y)];
    }

    for (int i = 1; i <= m; i++)
        cout << ans[i] << endl;
}

15.二分

#include<bits/stdc++.h>
#define N 2000005
using namespace std;

int n,m,l,ans,a[N];

int judge(int x){
    int s=0,num=0;
    for(int i=1;i<=n;i++){
        if(a[i]-s<x) num++;
        else s=a[i];
    }
    if(num>m) return 0;
    return 1;
}

int main(){
    scanf("%d%d%d",&l,&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    a[n+1]=l;
    int le=0,ri=l;
    while(le<=ri){
        int mid=le+ri>>1;
        if(judge(mid)){
            le=mid+1;
            ans=mid;
        }
        else ri=mid-1;
    }
    printf("%d",ans);
}

16.堆

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
int n, m,a[N];  // n表示堆里还有多少个节点,n是变的,所以弄个不变的m

void update(int x) {  //左移代表乘以二,就代表左儿子 //x<<1|1表示乘以二加一
    if ((x << 1) > n)
        return;
    int y = x << 1;  //如果只有一个儿子,y就是唯一的儿子,如果有两个,y就是更大的那个儿子
    if ((y | 1) <= n && a[y | 1] < a[y])
        y = y | 1;
    if (a[y] >= a[x])
        return;
    swap(a[x], a[y]);
    update(y);
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = n >> 1; i >= 1; i--) update(i);
    for (int i = 1; i <= m; i++) {
        int temp;
        scanf("%d", &temp);
        if (temp == 1) {
            scanf("%d", &a[++n]);
            for (int i = n >> 1; i >= 1; i = i >> 1) update(i);
        } else if (temp == 2) {
            printf("%d", a[1]);
            puts("");
            swap(a[1], a[n]);
            n--;
            update(1);
        }
    }
}

17.单调队列

 

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
int ai[N], maxq[N], minq[N];
int n, m, c, ahead, ihead, ansn, atail = 1, itail = 1;

int main() {
    scanf("%d%d%d",&n, &m, &c);
    for (int i = 1; i <= n; i++) scanf("%d", ai + i);
    
    for (int i = 1; i <= n; i++) {
        while (ahead >= atail && ai[maxq[ahead]] <= ai[i]) --ahead;
         
        ++ahead;
        maxq[ahead] = i;
         
        while (ihead >= itail && ai[minq[ihead]] >= ai[i]) --ihead;
         
        ++ihead;
        minq[ihead] = i;
         
        if (maxq[atail] <= i - m) ++atail;
        if (minq[itail] <= i - m) ++itail;
        
        if (i >= m)
            if (ai[maxq[atail]] - ai[minq[itail]] <= c) {
                printf("%d\n", i - m + 1);
                ++ansn;
            }
    }
    if(!ansn)
        printf("NONE");
}

 

18.欧几里得(辗转相除)

ll gcd(ll a, ll b) { return !b ? a : gcd(b, a%b); }

19.扩展欧几里得

 

 青蛙的约会:https://www.luogu.org/problem/P1516

int exgcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1, y = 0;
        return a; 
    } 
    int ret = exgcd(b, a%b, x, y);
    int tmp = x;
    x = y;
    y = tmp - a/b*y;
    return ret;
}

20.差分、前缀和

·区间修改后询问 http://oj.ipoweru.cn/problem/24200

#include <bits/stdc++.h>
using namespace std;
typedef long long lld;

const int N = 1e6 + 9;
int n, m, q;
lld a[N], d[N], s[N];

int main() {
    scanf("%d%d%d", &n, &m, &q);
    for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
    for (int i = 1; i <= n; ++i) d[i] = a[i] - a[i - 1];
    for (int i = 1, x, y, z; i <= m; ++i) {
        scanf("%d%d%d", &x, &y, &z);
        d[y + 1] -= z;
        d[x] += z;
    }
    for (int i = 1; i <= n; ++i) a[i] = a[i - 1] + d[i];
    for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
    for (int i = 1, x, y; i <= q; ++i) {
        scanf("%d%d", &x, &y);
        printf("%lld\n", s[y] - s[x - 1]);
    }
}

21.分解质因数

#include <bits/stdc++.h>
#define int long long
using namespace std;

int T, n, t, sta[1000000], tot;

int mul(int a, int b, int mod) {
    int ans = 0;
    while (b) {
        if (b & 1)
            ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}

int g(int x, int mod, int c) { return (mul(x, x, mod) + c) % n; }

int qpow(int a, int b, int mod) {
    int ans = 1;
    while (b) {
        if (b & 1)
            ans = mul(ans, a, mod);
        b >>= 1;
        a = mul(a, a, mod);
    }
    return ans;
}

bool MillerRabin(int n) {
    if (n == 2)
        return 1;
    if (n < 2 || !(n & 1))
        return 0;
    int m = n - 1, k = 0;
    while (!(m & 1)) {
        k++;
        m >>= 1;
    }
    for (int i = 1; i <= 3; i++) {
        int a = rand() % (n - 1) + 1;
        int x = qpow(a, m, n);
        int y;
        for (int j = 1; j <= k; j++) {
            y = mul(x, x, n);
            if (y == 1 && x != 1 && x != n - 1)
                return 0;
            x = y;
        }
        if (y != 1)
            return 0;
    }
    return 1;
}

int check(int n, int c) {
    int a = 2, b = a,p = 1;
    do {
        a = g(a, n, c);
        b = g(g(b, n, c), n, c);
        p = __gcd(abs(a - b), n);
        if (p != 1) break;
    } while (a != b);
    if (a == b) return 0;
    else return p;
}

void solve(int n) {
    while (n % 2 == 0) {  // n为偶数
        n /= 2;
        sta[++tot] = 2;
    } 
    if (n == 1)
        return;
    if (MillerRabin(n))
        sta[++tot] = n;
    else {
        int d = n;
        int i = 1;
        while (i++) {
            d = check(n, i);
            if (d != n)
                break;
        }
        solve(d);
        solve(n / d);
    }
}

signed main() {
    srand(time(0));
    cin >> T;
    while (T--) {
        tot = 0;
        cin >> n;
        solve(n);
        sort(sta + 1, sta + tot + 1);
        for (int i = 1; i <= tot; i++) {
            cout << sta[i] << " ";
        }
        cout << endl;
    }
}

22.卷积式

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 3505;
int T, n, m, q;
ll f[N], g[N];

void work(int n) {
    if (n == 1) return;
    
    if (!(n & 1)) {//n&1判断奇偶.当n为奇数时,返回1;当n为偶数时,返回0
        //为偶数 
        work(n / 2);
        
        for (int i = 0; i <= m; i++) {
            g[i] = 0;
            for (int j = 0; j <= i; j++) 
                g[i] += f[j] % q * f[i - j] % q;
            g[i] %= q;
        }
        
        for (int i = 0; i <= m; i++) 
            f[i] = g[i];
            
    } else { //奇数 
        work(n - 1);
        
        for (int i = 1; i <= m; i++) {
            g[i] = f[i - 1] % q + f[i] % q;
            g[i] %= q;
        }
        
        for (int i = 1; i <= m; i++) 
            f[i] = g[i];
            
    }
}

signed main() {
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d%d",&n,&m,&q);
        memset(f, 0, sizeof f);
        f[0] = f[1] = 1;
        work(n);
        for (int i = 0; i <= m; i++)
            printf("%lld ",f[i] % q);
        puts("");
    }
}

23.容斥原理

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N=2003;
int n, m, f[N][N], a[N], c[N];
ll p, ans;

void getpre() {
    for (int i = 0; i <= n + 1; i++) {
        f[i][0] = 1;
        f[i][i] = 1;
    }
    for (int i = 1; i <= n + 1; i++)
        for (int j = 1; j <= i; j++)
            f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % p;
}

void dfs(int k, int s, int sum) {
    if (sum <= 0) return;
    if (k == m + 1) {
        ans = (ans + s * f[sum - 1][m - 1] % p + p) % p;
        return;
    }
    dfs(k + 1, s, sum);
    dfs(k + 1, -s, sum - c[k] - 1);
}

int main() {
    scanf("%d%d%lld", &m, &n, &p);
    int num = 0;
    getpre();

    for (int i = 1; i <= m; i++) {
        scanf("%d%d",&a[i],&c[i]);
        c[i] -= a[i];
        num += a[i];
    }

    dfs(1, 1, n + m - num);
    printf("%lld", ans);
}

 24.重载

//重载运算符比较大小
struct node {  int len;   
   bool operator <(const node &a)const {//重载<操作符。可以对两个node使用<操作符进行比较
       return len<a.len;
   }
};

 

 

posted @ 2019-11-09 15:24  攒一兜星星*  阅读(184)  评论(0编辑  收藏  举报