史上最细!元歌教学

竞赛结束了,现在将竞赛所有的内容进行一下汇总,并将所有能用的模版代码写于此,PPT中有详细的算法思路的解释,所以在此不再赘述,只有模版代码,务必记熟!
贪心没有模版,就不写了QAQ
二分模版也不是很难记,也不写了QAQ
从三分开始
三分(求单峰函数最值):

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
double l,r;
struct function{
    int mi;
    double xi;
}a[1000001];
double f(double x){
    double ans = 0;
    for(int i = 1;i <= n + 1; i++){
        ans = ans + a[i].xi * pow(x,a[i].mi);
    }
    return ans;
}
int main(){
    scanf("%d" ,&n);
    scanf("%lf %lf" ,&l,&r);
    int k = n;
    for(int i = 1;i <= n + 1; i++){
        a[i].mi = k;
        k--;
    }
    for(int i = 1;i <= n + 1; i++){
        scanf("%lf" ,&a[i].xi);
    }
    double smid,emid;
    double st = l,ed = r;
    while(ed - st > 0.00001){
        double mid = (st + ed) / 2;
        smid = mid;
        emid = mid + 0.000001;
        if(f(smid) > f(emid)){
            ed = emid;
        }
        if(f(smid) < f(emid)){
            st = smid;
        }
        if(f(smid) == f(emid)){
            st = smid;
            ed = emid;
        }
    }
    printf("%.5lf" ,st);
    return 0;
}

快速幂(配上取模):

#include<cstdio>
using namespace std;
long long int n,p,k;
long long int mi(long long int x,long long int y,long long int z){
	long long int res = 1;
	while(y){
		if(y % 2 == 1) res = res * x % z;
		x = x * x % z;
		y = y / 2;
	}
	return res;
}
int main()
{
	scanf("%lld %lld %lld" ,&n,&p,&k);
	printf("%lld^%lld mod %lld=%lld" ,n,p,k,mi(n,p,k) % k);
	return 0;
}

ST表(这个东西不但原理复杂还不好记,要多看看)
一维:

#include<cstdio>
#include<algorithm>
using namespace std;
int a[1000001] = { };
int ans[1000001] = { };
int dp[100501][17] = { };
int que[100501] = { };
int m,n;
int query(int l,int r){
    int k = que[r - l + 1];
    return max(dp[l][k],dp[r - (1 << k) + 1][k]);
}
int main(){
    scanf("%d %d" ,&n,&m);
    for(int i = 1;i <= n; i++){
        scanf("%d" ,&a[i]);
    }
    for(int i = 1;i <= n; i++){
        dp[i][0] = a[i];
    }
    for(int j = 1;1 << j <= n; ++j){
        for(int i = 1;i + (1 << j) - 1 <= n; ++i){
            dp[i][j] = max(dp[i][j - 1],dp[i + (1 << (j - 1))][j - 1]);
        }
    }
    int k = 0;
    for(int i = 1;i <= n; ++i){
        if((1 << k) <= i) k++;
        que[i] = k - 1;
    }
    int h = 1;
    for(int i = 1;i <= m; i++){
        int x,y;
        scanf("%d %d" ,&x,&y);
        printf("%d\n" ,query(x,y));
    }
    return 0;
}

二维:

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int a,b,n;
int ma[1010][1010][9] = { },mi[1010][1010][9] = { };
int que[1001] = { };
int ans[1010][1010] = { };
int ac[1010][1010] = { };
int max4(int a,int b,int c,int d){
    return max(a,max(b,max(c,d)));
}
int min4(int a,int b,int c,int d){
    return min(a,min(b,min(c,d)));
}
int l[1001] = { };
int query(int x,int y){
    int k = que[y - x + 1];
    int p,q;
    p=max4(ma[x][y][k],ma[x + n - (1 << k)][y][k],ma[x][y + n - (1 << k)][k],ma[x + n - (1 << k)][y + n - (1 << k)][k]);
    q=min4(mi[x][y][k],mi[x + n - (1 << k)][y][k],mi[x][y + n - (1 << k)][k],mi[x + n - (1 << k)][y + n - (1 << k)][k]);
    return p - q;
}
int main(){
    scanf("%d %d %d" ,&a,&b,&n);
    for(int i = 1;i <= a; i++){
        for(int j = 1;j <= b; j++){
            scanf("%d" ,&ac[i][j]);
        }
    }
    for(int i = 1;i <= a; i++){
        for(int j = 1;j <= b; j++){
            ma[i][j][0] = mi[i][j][0] = ac[i][j];
        }
    }
    l[0]=1;
    for(int i=1;i<=18;i++){
        l[i]=l[i-1] * 2;
    }
    int p = 0;
    while(l[p + 1] <= n){
        p++;
    }
    for(int k = 1;k <= p; k++){
        for(int i = 1;i + (1 << k) - 1 <= a; i++){
            for(int j = 1;j + (1 << k) - 1 <= b; j++){
                ma[i][j][k]=max4(ma[i][j][k-1],ma[i + (1 << (k - 1))][j][k-1],
                                ma[i][j + (1 << (k - 1))][k-1],ma[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
                mi[i][j][k]=min4(mi[i][j][k - 1],mi[i + (1 << (k - 1))][j][k - 1],
                                mi[i][j + (1 << (k - 1))][k-1],mi[i + (1 << (k - 1))][j + (1 << (k - 1))][k - 1]);
            }
        }
    }
    int k = 1; //原来是k = 0;
    for(int i = 1;i <= n; ++i){
        if((1 << k) <= i) k++;
        que[i] = k - 1;
    }
    int xiao = 1e10 - 1;
    for(int i = 1;i + n - 1 <= a; i++){
        for(int j = 1;j + n - 1<= b; j++){
            if(query(i,j) < xiao) xiao = query(i,j); ///!
        }
    }
    printf("%d\n" ,xiao);
    return 0;
}

STL应用没有什么模版,等这个明天再做一个专题专门总结一下学过的STL
栈和队列竟然也没有模版QAQ
接下来是图论:
图的遍历:

#include<cstdio>
#include<cstring>
using namespace std;
int n,m;
struct Edge{
    int nxt,to;
}e[100001];
int a[1000001] = { };
int head[1000001],ecnt = 0;
void addEdge(int x,int y){
    ++ecnt;
    e[ecnt].nxt = head[x];
    e[ecnt].to = y;
    head[x] = ecnt;
}
void dfs(int now,int p){
    a[now] = p;
    for(int i = head[now],v;~i; i = e[i].nxt){
        if(a[v = e[i].to]) continue;
        dfs(v,p);
    }
}
int main(){
    scanf("%d %d" ,&n,&m);
    memset(head,-1,sizeof(head));
    for(int i = 1;i <= m; i++){
        int x,y;
        scanf("%d %d" ,&x,&y);
        addEdge(y,x);
    }
    
    for(int i = n;i; i--){
        if(!a[i]) dfs(i,i);
    }
    for(int i = 1;i <= n; i++) printf("%d " ,a[i]);
    return 0;
}

记录路径数量:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int mod=80112002;
int n,m,cnt=0;
struct edge
{
    int to,nxt;
}edge[500005];
int head[500005],vis[500005],in[500005],out[500005],sum[500005];
void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}
int main()
{
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;
        add(x,y);
        in[y]++;
        out[x]++;
    }
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        if(!in[i])
        {
            q.push(i);
            sum[i]=1;
        }
    }
    int ans=0;
    while(!q.empty())
    {
        int v=q.front();
        q.pop();
        for(int i=head[v];i;i=edge[i].nxt)
        {
            int k=edge[i].to;
            sum[k]=(sum[k]+sum[v])%mod;
            in[k]--;
            if(in[k]==0)
            {
                q.push(k);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(out[i]==0)
        {
            ans=(ans+sum[i])%mod;
        }
    }
    cout<<ans<<endl;
}

一个类似拓扑排序的应用(这道题原题是洛谷P1347)

#include<cstdio>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<string.h>
using namespace std;
int n,m;
struct Node{
    int u;
    int val;
    Node(int u = 0 , int val = 0 ):u(u),val(val){}
};
vector<int> vec[50];
int ru[50];
int sum;
int ans;
int k;
set<int> s1;
void print(){
    for(int i = 1 ; i <= n ; i++)printf("%c",(char)(i+'A'-1));
}
int have;
void topo(){
    queue<Node> q;
    for(int i = 0 ; i < 26; i++){
        if(ru[i] == 0 && s1.count(i)){
            q.push(Node(i,1));
            sum++;
        }
    }
    while(!q.empty()){
        int u = q.front().u;
        int val = q.front().val;
        q.pop();
        for(int i = 0; i < vec[u].size(); i++){
            int v = vec[u][i];
            ru[v]--;
            if(ru[v]==0){
                sum++;
                q.push(Node(v,val+1));
                ans=max(ans,val+1);
            }
        }
    }
    if(ans == n){
        printf("Sorted sequence determined after %d relations: ",k);
        print();
        cout<<".";
        exit(0);
    }
    if(sum != have){
        printf("Inconsistency found after %d relations.",k);
        exit(0);
    }
}
int ru2[50];
int main(){
    cin >> n >> m;
    for(int i = 1 ; i <= m ; i++){
        string s;
        cin >> s;
        k = i;
        vec[s[0]-'A'].push_back(s[2]-'A');
        s1.insert(s[0]-'A');
        s1.insert(s[2]-'A');
        have = s1.size();
        ru2[s[2]-'A']++;
        sum = 0;
        ans = 0;
        memcpy(ru,ru2,sizeof(ru2));
        topo();
    }
    printf("Sorted sequence cannot be determined.");
    return 0;
}

图的dfs和bfs:

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+5;
vector<int> graph[maxn];
int flag[maxn];
void dfs(int v)
{
    flag[v]=true;
    cout<<v<<" ";
    for(int i=0;i<graph[v].size();i++)
    {
        if(!flag[graph[v][i]])
        {
            dfs(graph[v][i]);
        }
    }
}
void bfs(int v)
{
    queue<int>t;
    t.push(v);
    flag[v]=true;
    while(!t.empty())
    {
        int v1=t.front();
        t.pop();
        cout<<v1<<" ";
        for(int i=0;i<graph[v1].size();i++)
        {
            if(!flag[graph[v1][i]])
            {
                t.push(graph[v1][i]);
                flag[graph[v1][i]]=true;
            }
        }
    }
}
int main()
{
    int n,m,v1,v2;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>v1>>v2;
        graph[v1].push_back(v2);
    }
    for(int i=1;i<=n;i++)
    {
        sort(graph[i].begin(),graph[i].end());
    }
    memset(flag,false,sizeof(flag));
    dfs(1);
    memset(flag,false,sizeof(flag));
    cout<<endl;
    bfs(1);
    return 0;
}

单源最短路DJ哥斯拉优化版:

#include<cstring>
#include<cstdio>
#include<queue>
#include<iostream>
#include<utility>
#include<algorithm>
using namespace std;
typedef pair<int,int> pr;
struct Edge{
    int nxt,to,w;
}e[300001];
struct cmp
{
    bool operator()(const pr p1,const pr p2)
    {
        return p1.second < p2.second;
    }
};
int n,m,s;
int head[300001];
int ecnt = 0;
int dis[300001] = { };
priority_queue<pr, vector<pr>, greater<pr> > q;
void addEdge(int x,int y,int w){
    ++ecnt;
    e[ecnt].nxt = head[x];
    e[ecnt].w = w;
    e[ecnt].to = y;
    head[x] = ecnt;
}
int vis[300001] = { };
void dijkstra()
{
    memset(dis, 0x3f,sizeof(dis));
    dis[1] = 0;
    q.push(make_pair(0, s));
    while(!q.empty())
    {
        int now = q.top().second; q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(int i = head[now]; ~i; i = e[i].nxt)
        {
            int v = e[i].to;
            if(dis[v] > dis[now] + e[i].w)
            {
                dis[v] = dis[now] + e[i].w;
                q.push(make_pair(dis[v], v));
            }
        }
    }
}
int main(){
    scanf("%d %d %d" ,&n,&m,&s);
    memset(head,-1,sizeof(head));
    for(int i = 1;i <= m; i++){
        int a,b,c;
        scanf("%d %d %d" ,&a,&b,&c);
        addEdge(a,b,c);
    }
    dijkstra();
    for(int i = 1;i <= n; i++){
        printf("%d " ,dis[i]);
    }
    return 0;
}

DJ哥斯拉优化版最短路计数:

#include<cstring>
#include<cstdio>
#include<queue>
#include<iostream>
#include<utility>
#include<algorithm>
using namespace std;
int dis[3000001] = { };
struct Edge{
    int nxt,to,w;
}e[1000001];
int head[100001];
int ecnt = 0;
typedef pair<int,int> pr;
struct cmp
{
    bool operator()(const pr p1,const pr p2)
    {
        return p1.second < p2.second;
    }
};
void addEdge(int x,int y){
    ++ecnt;
    e[ecnt].nxt = head[x];
    e[ecnt].w = 1;
    e[ecnt].to = y;
    head[x] = ecnt;
}
int n,m;
int vis[3000001] = { };
int s = 1;
int ans[1000001] = { };
priority_queue<pr, vector<pr>, greater<pr> > q;
void dijkstra()
{
    memset(dis, 0x3f,sizeof(dis));
    dis[1] = 0;
    ans[1] = 1;
    q.push(make_pair(0, s));
    while(!q.empty())
    {
        int now = q.top().second;
        int d = q.top().first;
        q.pop();
        //if(vis[now]) continue;
        if(d != dis[now]) continue;
        //vis[now] = 1;
        for(int i = head[now]; ~i; i = e[i].nxt)
        {
            int v = e[i].to;
            if(d + e[i].w == dis[v]){
                ans[v] = (ans[now] + ans[v]) % 100003;
            }
            if(dis[v] > dis[now] + e[i].w)
            {
                dis[v] = dis[now] + e[i].w;
                ans[v] = ans[now];
                q.push(make_pair(dis[v], v));
            }
        }
    }
}
int main(){
    scanf("%d %d" ,&n,&m);
    memset(head,-1,sizeof(head));
    for(int i = 1;i <= m; i++){
        int a,b;
        scanf("%d %d" ,&a,&b);
        if(a == b) continue;
        addEdge(a,b);
        addEdge(b,a);
    }
    dijkstra();
    for(int i = 1;i <= n; i++){
        printf("%d\n" ,ans[i]);
    }
    return 0;
}

分层图最短路(这个我一直理解的不好,有空要多看看,然后分层图最短路我在当日总结里提到过,到时候回去翻一下):
洛谷原题 P1948:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Edge{
    int nxt,to,w;
}e[20005];
int n,p,k,ecnt = 0;
int head[1005],dis[1005],q[1005];
bool jd[1005];
void addEdge(int x,int y,int w){
    ++ecnt;
    e[ecnt].nxt = head[x];
    e[ecnt].w = w;
    e[ecnt].to = y;
    head[x] = ecnt;
}
bool solve(int x){
    memset(dis,0x3f,sizeof(dis));
    int t = 0,w = 1,i,now,s;
    dis[1] = 0;
    q[t] = 1;
    jd[1] = 1;
    while(t != w){
        now = q[t];
        t++;
        if(t == 1001) t = 0;
        i = head[now];
        while(i){
            if(e[i].w > x) s = dis[now] + 1;
            else s = dis[now];
            if(s < dis[e[i].to]){
                dis[e[i].to] = s;
                if(!jd[e[i].to]){
                    q[w++] = e[i].to;
                    jd[e[i].to] = 1;
                    if(w == 1001) w = 0;
                }
                
            }
            i = e[i].nxt;
            
        }
        jd[now] = 0;
    }
    if(dis[n] <= k) return 1;
    return 0;
}
int main(){
    scanf("%d %d %d" ,&n,&p,&k);
    int a,b,c;
    int le = 0,ri = 1000000;
    for(int i = 1;i <= p; i++){
        scanf("%d %d %d" ,&a,&b,&c);
        addEdge(a,b,c);
        addEdge(b,a,c);
    }
    int ans = -1;
    while(le <= ri){
        int mid = (le + ri) >> 1;
        if(solve(mid)){
            ri = mid - 1;
            ans = mid;
        }
        else{
            le = mid + 1;
        }
    }
    printf("%d" ,ans);
    return 0;
}

判负环:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct Edge{
    int nxt,to,w;
}e[30001];
int head[30001];
int ecnt = -1;
int n,m;
void addEdge(int x,int y,int w){
    ++ecnt;
    e[ecnt].nxt = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}
int cnt[30001] = { };
int dis[10001] = { };
int vis[10001] = { };
int flag = 0;
void spfa()
{
	queue<int>q;
    memset(dis, 0x3f,sizeof(dis));
    memset(cnt, 0,sizeof(cnt));
    memset(vis, 0,sizeof(vis));
    dis[1] = 0;
    q.push(1);
    vis[1]=1;
    while(!q.empty())
    {
        int now = q.front(); q.pop();
        vis[now] = 0;
        for(int i = head[now]; ~i; i = e[i].nxt)
        {
            int v = e[i].to;
            if(dis[v] > dis[now] + e[i].w)
            {
                dis[v] = dis[now] + e[i].w;
                cnt[v]=cnt[now]+1;
                if(cnt[v] >= n){
                    printf("YES\n");
                    return;
                }
                if(!vis[v]) {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
    printf("NO\n");
}
int k;
int main(){
    scanf("%d" ,&k);
    for(int j = 1;j <= k; j++){
        memset(head,-1,sizeof(head));
        scanf("%d %d" ,&n,&m);
        ecnt=-1;
        for(int i = 1;i <= m; i++){
            int a,b,c;
            scanf("%d %d %d" ,&a,&b,&c);
            addEdge(a,b,c);
            if(c>=0) addEdge(b,a,c);
        }
        spfa();
    }
}


LCA(最近公共祖先):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 5e5 + 5;

int n, m, s;
struct Edge
{
    int nxt, to;
}e[maxn << 1];
int head[maxn], ecnt = -1;
void addEdge(int x, int y)
{
    e[++ecnt] = (Edge){head[x], y};
    head[x] = ecnt;
}

int dep[maxn], Dfs[2 * maxn], fir[maxn];
int cnt = 0;
void dfs(int u, int _f)
{
    Dfs[++cnt] = u; fir[u] = cnt;
     for(int i = head[u]; ~i; i = e[i].nxt)
    {
        int v = e[i].to;
        if(v == _f) continue;
        dep[v] = dep[u] + 1;
        dfs(v, u);
        Dfs[++cnt] = u;
    }
}

int que[maxn << 1];
struct Node {int Min, pos;}dp[2 * maxn][25];
void init()
{
    for(int i = 1; i <= cnt; ++i) dp[i][0] = (Node){dep[Dfs[i]], Dfs[i]};
    for(int j = 1; (1 << j) <= cnt; ++j)
        for(int i = 1; i + (1 << j) - 1 <= cnt; ++i)
        {
            if(dp[i][j - 1].Min < dp[i + (1 << (j - 1))][j - 1].Min) dp[i][j] = dp[i][j - 1];
            else dp[i][j] = dp[i + (1 << (j - 1))][j - 1];
        }
    for(int i = 2; i <= cnt; ++i) que[i] = que[i >> 1] + 1;
}
int lca(int x, int y)
{
    int L = fir[x], R = fir[y];
    if(R < L) swap(L, R);
    int k = que[R - L + 1];
    if(dp[L][k].Min < dp[R - (1 << k) + 1][k].Min) return dp[L][k].pos;
    else return dp[R - (1 << k) + 1][k].pos;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &m, &s);
    for(int i = 1; i < n; ++i)
    {
        int x, y; scanf("%d%d", &x, &y);
        addEdge(x, y);
        addEdge(y, x);
    }
    dep[1] = 1;
    dfs(s, 0);
    init();
    for(int i = 1; i <= m; ++i)
    {
        int x, y; scanf("%d%d", &x, &y);
        printf("%d\n", lca(x, y));
    }
    return 0;
}

树状数组:

#include <iostream>
  #include <cstdio>
  #include <algorithm>
  #include <cmath>
  #include <cstring>
  using namespace std;
  int n,m,tree[2000010];
  int lowbit(int k)
  {
      return k & -k;
  }
  void add(int x,int k)
  {
      while(x<=n)
      {
          tree[x]+=k;
          x+=lowbit(x);
      }
  }
  int sum(int x)
  {
      int ans=0;
      while(x!=0)
      {
          ans+=tree[x];
          x-=lowbit(x);
      }
      return ans;
  }
  int main()
  {
      scanf("%d %d" ,&n,&m);
      for(int i=1;i<=n;i++)
      {
          int a;
          scanf("%d",&a);
          add(i,a);
      }
      for(int i=1;i<=m;i++)
      {
          int a,b,c;
          scanf("%d%d%d",&a,&b,&c);
          if(a==1)
              add(b,c);   //将第b个数加上c
          if(a==2)
              printf("%d\n" ,sum(c)-sum(b-1));  //输出区间[b,c]内的和
      }
      return 0;
  }

并查集:

#include<cstdio>
using namespace std;
int p[100001] = { };
int n,m;

int Find(int x)
{
    return x == p[x] ? x : p[x] = Find(p[x]);
}
void merge(int x, int y)
{
    int px = Find(x), py = Find(y);
    if(px == py) return;
    p[px] = py;
}
int main(){
    scanf("%d %d" ,&n,&m);
    for(int i = 1;i <= n; i++){
        p[i] = i;
    }
    for(int i = 1;i <= m; i++){
        int z;
        scanf("%d" ,&z);
        if(z == 1){
            int y,x;
            scanf("%d %d" ,&x,&y);
            merge(x,y);//将x,y合并
        }
        if(z == 2){
            int x,y;
            scanf("%d %d" ,&x,&y);
            if(Find(x) == Find(y)) printf("Y\n"); //看x和y是否在一个集合中
            else printf("N\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值