noip模板整理

距离noip还有⑨-1天,差不多要开始撸模板了,在这里整理下noip各式各样算法的模板。

图论 :

(论图╮(╯▽╰)╭)

spfa:图上乱搞必备,并非只止步于求最短路 | 最长路,spfa可是图上dp!!
noip模板整理_第1张图片

#include
#include
#include
#include
#include
using namespace std;
const int sz = 200100;
deque < int > q; // slf
int n,m;
int head[sz],nxt[sz],dist[sz];
struct gtnd
{
    int t,d;
}l[sz];
int tot = 1;
bool use[sz];
int pre[sz];//记录路径
int tim[sz];//判负环 
void build(int f,int t,int d)
{
    l[tot].t = t;
    l[tot].d = d;
    nxt[tot] = head[f];
    head[f] = tot ++;
}
int spfa(int s,int e)
{
    for(int i = 1 ; i <= n ; i ++)
        dist[i] = 2147483641;
    dist[s] = 0;
    use[s] = 1;
    q.push_front(s);
    while(!q.empty())
    {
        int f = q.front();
        q.pop_front();
        use[f] = 0;
        for(int i = head[f] ; i ; i = nxt[i])
        {
            int t = l[i].t;
            if(dist[t] > dist[f] + l[i].d)
            {
                dist[t] = dist[f] + l[i].d;
                tim[t] = tim[f] + 1;
                if(tim[t] > n)
                    return -1;
                pre[t] = f;
                if(!use[t])
                {
                    use[t] = 1;
                    if(!q.empty())
                    {
                        if(dist[t] < dist[q.front()])
                            q.push_front(t);
                        else
                            q.push_back(t);
                    }
                    else
                        q.push_back(t);
                }
            }
        }
    }
    return dist[e];
}
void print_path(int u) // 打印路径 
{
    printf("%d ",u);
    if(pre[u])
        print_path(pre[u]);
}
int main()
{

    return 0;
}

Kruskal,最小生成树,好像可以跟01分数规划搞一搞?
noip模板整理_第2张图片

#include
#include
#include
#include
using namespace std;
const int sz = 200010;
int f[sz];
int n,m;
int find(int x)
{
    if(f[x] == x)
        return x;
    return f[x] = find(f[x]);
}
struct gtnd
{
    int f,t,d;
}l[sz];
bool cmp(gtnd swc,gtnd zcw)
{
    return swc.d > zcw.d; 
}
int Kruskal()
{
    int ans = 0;
    for(int i = 1 ; i <= n ; i ++)
        f[i] = i;
    sort(l+1,l+m+1,cmp);
    for(int i = 1 ; i <= m ; i ++)
    {
        int u = l[i].f , v = l[i].t;
        int fu = find(u) , fv = find(v);
        if(fu != fv)
        {
            f[fu] = fv;
            ans += l[i].d;
        }
    }
    return ans;
}
int main()
{


    return 0;
}

拓扑排序,图上dp有时会用到╮(╯▽╰)╭。
noip模板整理_第3张图片

#include
#include
#include
#include
#include
using namespace std;
const int sz = 200010;
int head[sz],nxt[sz],l[sz];
int ru[sz];
int tot = 1;
int n,m;
queue < int > q;
void build(int f,int t)
{
    l[tot] = t;
    nxt[tot] = head[f];
    head[f] = tot ++;
}
void top_sort()
{
    for(int i = 1 ; i <= n ; i ++)
        if(!ru[i])
        {
            q.push(i);
            printf("%d ",i);
        }
    while(!q.empty())
    {
        int f = q.front();
        q.pop();
        for(int i = head[f] ; i ; i = nxt[i])
        {
            ru[l[i]] --;
            if(!ru[l[i]])
            {
                printf("%d ",l[i]);
                q.push(l[i]);
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1 ; i <= m ; i ++)
    {
        int f,t;
        scanf("%d%d",&f,&t);
        ru[t] ++;
        build(f,t);
    }
    top_sort();
    return 0;
}

树上最近公共祖先,lca,这里推荐倍增版,滋磁在树上快速搞事。
noip模板整理_第4张图片

#include
#include
#include
#include
using namespace std;
const int size = 200010;
int head[size],next[size],dist[size][32];
int par[size][32],deep[size];
int tot = 1;
struct dc
{
    int t,d;
}l[size];
void build(int f,int t,int d)
{
    l[tot].t = t;
    l[tot].d = d;
    next[tot] = head[f];
    head[f] = tot ++;
}
int n;
void dfs(int u,int fa,int dep,int dis)
{
    par[u][0] = fa;
    dist[u][0] = dis;
    deep[u] = dep;
    for(int i = head[u] ; i ; i = next[i])
    {
        int v = l[i].t;
        if(v != fa)
            dfs(v,u,dep+1,l[i].d);
    }
}
int lca(int u,int v)
{
    int ans = 0;
    if(deep[u] < deep[v])
        swap(u,v);
    for(int i = 31 ; i >= 0 ; i --)
        if(deep[par[u][i]] >= deep[v])
            ans += dist[u][i] , u = par[u][i];
    for(int i = 31 ; i >= 0 ; i --)
        if(par[u][i] != par[v][i])
            ans += dist[u][i] + dist[v][i] , u = par[u][i] , v = par[v][i];
    if(u != v)
        ans += dist[u][0] + dist[v][0] , u = par[u][0] , v = par[v][0];
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i = 1 ; i < n ; i ++)
    {
        int f,t,d;
        scanf("%d%d%d",&f,&t,&d);
        f ++ , t ++;
        build(f,t,d);
        build(t,f,d);
    }
    dfs(1,0,1,0);
    for(int i = 1 ; i <= 31 ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            par[j][i] = par[par[j][i-1]][i-1] , dist[j][i] = dist[j][i-1] + dist[par[j][i-1]][i-1];
    int m;
    scanf("%d",&m);
    for(int i = 1 ; i <= m ; i ++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u+1,v+1));
    }
    return 0;
}

tarjan系列
noip模板整理_第5张图片
tarjan 求 scc , 有向图大腿。

#include
#include
#include
#include
#include
using namespace std;
const int sz = 200010;
int head[sz],nxt[sz],dist[sz],l[sz];
int low[sz],dfn[sz],scc_num,dfs_clock;
stack < int > s;
struct gtnd
{
    int p,num;
    bool operator <(const gtnd &a)const
    {
        return num < a.num;
    }
}scc[sz];
int tarjan(int u)
{
    dfn[u] = low[u] = dfs_clock ++;
    s.push(u);
    for(int i = head[u] ; i ; i = nxt[i])
    {
        int v = l[i];
        if(!dfn[v])
        {
            low[v] = tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!scc[v].num)
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_num ++;
        while(12 < 450)
        {
            if(s.empty())
                break;
            int v = s.top();
            s.pop();
            scc[v].num = scc_num;
            scc[v].p = v;
            if(u == v)
                break;
        }
    }
    return low[u];
}
int main()
{

    return 0;
}

tarjan求割点,然而基本没用过,忘得差不多了。

#include
#include
#include
#include
#include
using namespace std;
const int sz = 200010;
int head[sz],nxt[sz],l[sz];
int tot = 1;
int n,m;
void build(int f,int t)
{
    l[tot] = t;
    nxt[tot] = head[f];
    head[f] = tot ++;
}

int low[sz],dfn[sz],dfs_clock;
bool is_cut[sz];
int tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++ dfs_clock;
    int child = 0;
    for(int i = head[u] ; i ; i = nxt[i])
    {
        int v = l[i];
        if(!dfn[v])
        {
            child ++;
            low[v] = tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(dfn[u] <= low[v])
                is_cut[u] = 1;
        }
        else if(dfn[v] < dfn[u] && v != fa)
            low[u] = min(dfn[v],low[u]);
    }
    if(child == 1 && fa == 0)
        is_cut[u] = 0;
    return low[u];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1 ; i <= m ; i ++)
    {
        int f,t;
        scanf("%d%d",&f,&t);
        build(f,t);
        build(t,f);
    }
    for(int i = 1 ; i <= n ; i ++)
        if(!dfn[i])
            tarjan(i,0);
    int ans = 0;
    for(int i = 1 ; i <= n ; i ++)
        if(is_cut[i])
            ans ++;
    printf("%d\n",ans);
    for(int i = 1 ; i <= n ; i ++)
        if(is_cut[i])
            printf("%d ",i);
    return 0;
}

tarjan求桥,就是割点改个等于号。

int low[sz],dfn[sz],dfs_clock;
struct gtnd
{
    int f,t;
}cut[sz];
int conut;
int tarjan(int u,int fa)
{
    dfn[u] = low[u] = ++ dfs_clock;
    int child = 0;
    for(int i = head[u] ; i ; i = nxt[i])
    {
        int v = l[i];
        if(!dfn[v])
        {
            child ++;
            low[v] = tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(dfn[u] < low[v])
                cut[++conut].f = u , cut[count].t = v;
        }
        else if(dfn[v] < dfn[u] && v != fa)
            low[u] = min(dfn[v],low[u]);
    }
    return low[u];
}

树的直径,滋磁树上乱搞,这里以codevs1814为例。
noip模板整理_第6张图片

#include
#include
#include
#include
using namespace std;
int n;
const int size = 200010;
int head[size],next[size],l[size];
int tot = 1;
void build(int f,int t)
{
    l[tot] = t;
    next[tot] = head[f];
    head[f] = tot ++;
}
int pos,dist;
void dfs(int u,int p,int dis)
{
    if(dis > dist)
        dist = dis , pos = u;
    for(int i = head[u] ; i ; i = next[i])
    {
        int v = l[i];
        if(v != p)
            dfs(v,u,dis+1);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++)
    {
        int ll,rr;
        scanf("%d%d",&ll,&rr);
        if(ll)
            build(ll,i) , build(i,ll);
        if(rr)
            build(rr,i) , build(i,rr);
    }
    dfs(1,-1,0);
    dist = 0;
    dfs(pos,-1,0);
    printf("%d\n",dist);
    return 0;
} 

floyd,n^3最短路,带有比较特殊的性质,可以有各种变形,但往往难度超出noip范围。
noip模板整理_第7张图片

#include
#include
#include
#include
#define ll long long
using namespace std;
const int sz = 2550;
int dis[sz][sz];
int n,m,s,e;
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1 ; j <= n ; j ++)
            dis[i][j] = 214748364;
    for(int i = 1 ; i <= n ; i ++)
        dis[i][i] = 0;
    for(int i = 1 ; i <= m ; i ++)
    {
        int f,t,d;
        scanf("%d%d%d",&f,&t,&d);
        dis[f][t] = min(dis[f][t],d);
        dis[t][f] = min(dis[f][t],dis[t][f]);
    }
    for(int k = 1 ; k <= n ; k ++)
        for(int i = 1 ; i <= n ; i ++)
            for(int j = 1 ; j <= n ; j ++)
                dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
    printf("%d\n",dis[s][e]);
    return 0;
}

数论

暴力(划);

gcd & lcm ,noip唯有的几个可以加特技的算法。
noip模板整理_第8张图片

#include
#include
#include
#include
using namespace std;
int gcd(int a,int b)
{
    if(b == 0)
        return a;
    return gcd(b,a%b);
}
int lcm(int a,int b)
{
    return a * b / gcd(a,b);
}
int main()
{
    int a,b;
    while(scanf("%d%d",&a,&b))
    {
        printf("%d\n",gcd(a,b));
    }
    return 0;
}

埃氏筛,筛素数速度上仅次于欧拉筛。
noip模板整理_第9张图片

#include
#include
#include
#include
using namespace std;
bool is_prime[2000100];
int main()
{
    int n;
    scanf("%d",&n);
    is_prime[1] = 1;
    for(int i = 2 ; i <= n ; i ++)
    {
        if(!is_prime[i])
            for(int j = i * i ; j <= n ; j += i)
                is_prime[j] = 1;
    }
    return 0;
} 

快速幂,快速求一个数的次方,搞事必备
noip模板整理_第10张图片

#include
#include
#include
#include
using namespace std;
int ksm(int x,int p)
{
    if(p == 0)
        return 1;
    if(p == 1)
        return x;
    if(p == 2)
        return x * x;
    int temp = ksm(x,p/2);
    if(p % 2 == 1)
        return temp * temp * x;
    if(p % 2 == 0)
        return temp * temp;
}
int main()
{
    int x,p;
    while(scanf("%d%d",&x,&p))
        printf("%d\n",ksm(x,p));
    return 0;
}

逆元,只推荐费马小定理,要是noip题mod不是素数我就暴力!
费马小定理: 假如p是质数,且a,p互质,那么 a^(p-1)≡1(mod p)。
由此可得,a^(p-2) ≡ 1 / a (mod p),所以在mod p意义下,除以 a 等价于乘上 a^(p-2),即 a^(p-2) 为 a 的逆元。
noip模板整理_第11张图片

#include
#include
#include
#include
#define ll long long
using namespace std;
const int mod = 1000000007;
ll ksm(ll x,ll p)
{
    if(p == 0)
        return 1;
    if(p == 1)
        return x % mod;
    if(p == 2)
        return ((x%mod) * (x%mod))%mod;
    int temp = ksm(x,p/2) % mod;
    if(p % 2 == 1)
        return (((temp * temp) % mod) * (x%mod));
    if(p % 2 == 0)
        return (temp * temp) % mod;
}
int get(int a)
{
    return ksm(a,mod-2);
}
int main()
{

    return 0;
}

数据结构

单调队列,滋磁O(n)序列上搞事,多用于dp优化。

noip模板整理_第12张图片

#include
#include
#include
#include
#include
using namespace std;
const int sz = 2000100;
deque < int > q;
int num[sz];
int n,k;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d",&num[i]);
    for(int i = 1 ; i <= k ; i ++)
    {
        while(!q.empty() && num[q.back()] < num[i])
            q.pop_back();
        q.push_back(i);
    }
    printf("%d\n",num[q.front()]);
    for(int i = k + 1 ; i <= n ; i ++)
    {
        while(!q.empty() && q.front() < i - k + 1)
            q.pop_front();
        while(!q.empty() && num[q.back()] < num[i])
            q.pop_back();
        q.push_back(i);
        printf("%d\n",num[q.front()]);
    }
    return 0;
}

set,用于logn找前驱后继或当map使233,这里以noi openjudge的冷血格斗场为例。
noip模板整理_第13张图片

#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
struct gtnd
{
    ll id;
    ll p;
    bool operator <(const gtnd &a)const
    {
        return p < a.p;
    }
};
map < ll , ll > m;
set < gtnd > s;
set < gtnd > :: iterator f1,f2,temp;
int n;
int main()
{
    scanf("%d",&n);
    gtnd sta;
    sta.id = 1 , sta.p = 1000000000;
    m[sta.p] = 1;
    s.insert(sta);
    for(int i = 1 ; i <= n ; i ++)
    {
        gtnd nxt;
        scanf("%lld%lld",&nxt.id,&nxt.p);
        printf("%lld ",nxt.id);
        if(m[nxt.p])
        {
            printf("%lld\n",m[nxt.p]);
            m[nxt.p] = min(m[nxt.p],nxt.id);
            continue;
        }
        else
            m[nxt.p] = nxt.id;

        f1 = s.lower_bound(nxt);
        f2 = f1;
        f2 --;
        ll id_f1 = m[(*f1).p] , id_f2 = m[(*f2).p];
        ll a_f1 = abs((*f1).p - nxt.p) , a_f2 = abs((*f2).p - nxt.p);
        if(f2 == s.end())
            printf("%lld\n",id_f1);
        else if(f1 == s.end())
            printf("%lld\n",id_f2);
        else if(a_f1 > a_f2)
            printf("%lld\n",id_f2);
        else if(a_f1 < a_f2)
            printf("%lld\n",id_f1);
        else
        {
            if(id_f1 < id_f2)
                printf("%lld\n",id_f1);
            else
                printf("%lld\n",id_f2);
        }
        s.insert(nxt);
    }
    return 0;
}

线段树,noip考不到但是可以水分的大腿,滋磁区间快速搞事。

noip模板整理_第14张图片

#include
#include
#include
#include
#define ll long long
using namespace std;
const int sz = 200010;
struct xd_tree
{
    int l,r;
    ll sum,min,max,add;
}tree[sz*4];
int num[sz];
int n;
void updata(int p)
{
    tree[p].min = min(tree[p<<1].min,tree[p<<1|1].min);
    tree[p].max = max(tree[p<<1].max,tree[p<<1|1].max);
    tree[p].sum = tree[p<<1].sum + tree[p<<1|1].sum;
}
void build_tree(int p,int l,int r)
{
    tree[p].l = l , tree[p].r = r;
    if(l == r)
    {
        tree[p].min = tree[p].max = tree[p].sum = num[l];
        return ;
    }
    int mid = l + r >> 1;
    build_tree(p<<1,l,mid);
    build_tree(p<<1|1,mid+1,r);
    updata(p);
}
void spread(int p)
{
    if(tree[p].add)
    {
        tree[p<<1].sum += tree[p].add * (tree[p<<1].r - tree[p<<1].l + 1);
        tree[p<<1|1].sum += tree[p].add * (tree[p<<1|1].r - tree[p<<1|1].l + 1);
        tree[p<<1].min += tree[p].add;
        tree[p<<1|1].min += tree[p].add;
        tree[p<<1].max += tree[p].add;
        tree[p<<1|1].max += tree[p].add;
        tree[p<<1].add += tree[p].add;
        tree[p<<1|1].add += tree[p].add;
        tree[p].add = 0;
    }
    return ;
}
void change(int p,int l,int r,int x)
{
    if(l <= tree[p].l && tree[p].r <= r)
    {
        tree[p].sum += x * (tree[p].r - tree[p].l + 1);
        tree[p].max += x;
        tree[p].min += x;
        tree[p].add += x;
        return ;
    }
    spread(p);
    int mid = tree[p].l + tree[p].r >> 1;
    if(l <= mid)
        change(p<<1,l,r,x);
    if(r > mid)
        change(p<<1|1,l,r,x);
    updata(p);
}
ll ask_sum(int p,int l,int r)
{
    if(l <= tree[p].l && tree[p].r <= r)
        return tree[p].sum;
    spread(p);
    int mid = tree[p].l + tree[p].r >> 1;
    ll ans = 0;
    if(l <= mid)
        ans += ask_sum(p<<1,l,r);
    if(r > mid)
        ans += ask_sum(p<<1|1,l,r);
    return ans; 
}
ll ask_min(int p,int l,int r)
{
    if(l <= tree[p].l && tree[p].r <= r)
        return tree[p].min;
    spread(p);
    int mid = tree[p].l + tree[p].r >> 1;
    ll ans = 214748364111111ll;
    if(l <= mid)
        ans = min(ask_min(p<<1,l,r),ans);
    if(r > mid)
        ans = min(ask_min(p<<1|1,l,r),ans);
    return ans;
}
ll ask_max(int p,int l,int r)
{
    if(l <= tree[p].l && tree[p].r <= r)
        return tree[p].max;
    spread(p);
    int mid = tree[p].l + tree[p].r >> 1;
    ll ans = 0;
    if(l <= mid)
        ans = max(ask_max(p<<1,l,r),ans);
    if(r > mid)
        ans = max(ask_max(p<<1|1,l,r),ans);
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d",&num[i]);
    build_tree(1,1,n);
    return 0;
}

其它的一些奇怪的算法 | 姿势

逆序对 && 归并排序
归并排序求逆序对是唯有的几个比较高效的求逆序对算法(线段树:???),前几年noip有用到。
noip模板整理_第15张图片

#include
#include
#include
#include
#define ll long long
using namespace std;
const int sz = 2000100;
ll ans;
int n;
int num[sz];
int temp[sz];
void merge_sort(int l,int r)
{
    if(l == r)
        return ;
    int mid = l + r >> 1;
    merge_sort(l,mid) , merge_sort(mid+1,r);
    int p = l , pl = l , pr = mid + 1;
    while(pl <= mid || pr <= r)
    {
        if(pr > r || (pl <= mid && num[pl] <= num[pr]))
            temp[p ++] = num[pl ++];
        else
            temp[p ++] = num[pr ++] , ans += mid - pl + 1;
    }
    for(int i = l ; i <= r ; i ++)
        num[i] = temp[i];
    return ;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d",&num[i]);
    merge_sort(1,n);
    printf("%lld\n",ans);
    return 0;
}

状压搜索,noip还真没见过,模拟赛里倒是不少。
以HAOI2008移动玩具为例。
noip模板整理_第16张图片

#include
#include
#include
#include
#include
using namespace std;
bool use[2000100];
struct gtnd
{
    int k;
    int now;
};
queue < gtnd > q;
int st,ed;
void start_work()
{
    for(int i = 0 ; i < 16 ; i ++)
    {
        char ins = getchar();
        while(ins != '1' && ins != '0')
            ins = getchar();
        ins -= '0';
        st |= ( ins << i );
    }
    for(int i = 0 ; i < 16 ; i ++)
    {
        char ins = getchar();
        while(ins != '1' && ins != '0')
            ins = getchar();
        ins -= '0';
        ed |= ( ins << i );
    }
}
int bfs()
{
    gtnd star;
    star.k = st;
    star.now = 0;
    q.push(star);
    use[st] = 1;
    while(!q.empty())
    {
        gtnd f = q.front();
        q.pop();
        if(f.k == ed)
            return f.now;
        for(int i = 0 ; i < 16 ; i ++)
        {
            if((f.k >> i) & 1)
            {
                if(i > 3 && !((f.k >> (i-4)) & 1))
                {
                    gtnd nxt;
                    nxt.now = f.now + 1;
                    nxt.k = f.k;
                    nxt.k ^= (1 << i-4);
                    nxt.k ^= (1 << i);
                    if(!use[nxt.k])
                    {
                        use[nxt.k] = 1;
                        q.push(nxt);
                    }
                }
                if(i < 12 && !((f.k >> (i+4)) & 1))
                {

                    gtnd nxt;
                    nxt.now = f.now + 1;
                    nxt.k = f.k;
                    nxt.k ^= (1 << i+4);
                    nxt.k ^= (1 << i);
                    if(!use[nxt.k])
                    {
                        use[nxt.k] = 1;
                        q.push(nxt);
                    }
                }
                if(i % 4 != 0 && !((f.k >> (i-1)) & 1))
                {
                    gtnd nxt;
                    nxt.now = f.now + 1;
                    nxt.k = f.k;
                    nxt.k ^= (1 << i-1);
                    nxt.k ^= (1 << i);
                    if(!use[nxt.k])
                    {
                        use[nxt.k] = 1;
                        q.push(nxt);
                    }
                }
                if(i % 4 != 3 && !((f.k >> (i+1)) & 1))
                {
                    gtnd nxt;
                    nxt.now = f.now + 1;
                    nxt.k = f.k;
                    nxt.k ^= (1 << i+1);
                    nxt.k ^= (1 << i);
                    if(!use[nxt.k])
                    {
                        use[nxt.k] = 1;
                        q.push(nxt);
                    }
                }
            }
        }
    }
    return -1;
}
int main()
{
    start_work();
    printf("%d\n",bfs());
    return 0;
}

论如何正确地打开脑洞
noip模板整理_第17张图片
自己的码力实现不了的做法还是少想;
看数据范围估计复杂度,看有没有套路,有没有可以套的模型,看特殊的条件等等。

你可能感兴趣的:(代码模板)