【刷题】【记录】牛客题单

题单地址:

【237题】算法基础精选题单_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 (nowcoder.com)

【算法进阶题单】动态规划、数据结构、图论、数学_ACM竞赛_ACM/CSP/ICPC/CCPC/比赛经验/题解/资讯_牛客竞赛OJ_牛客网 (nowcoder.com)

 

第一章 模拟、枚举和贪心

模拟

NC16644 [NOIP2007]字符串的展开

#include<iostream>
#include<algorithm>
using namespace std;

//isalpha() 函数 
//默认是大小写英文字母,范围可改

//--情况,wa10%
bool isnumber(char ch)
{
    if(ch>='0' && ch<='9')
        return true;
    else return false;
}

string get_char(char l,char r,int p1,int p2,int p3)
{
    //减号两侧同为小写字母或同为数字,且按照ASCII码的顺序,减号右边的字符严格大于左边的字符。
    if( ( isalpha(l) && isalpha(r) && l<r ) || ( isnumber(l) && isnumber(r) && l<r ) )
    {
        string ans="";
        for(char t=l+1;t<r;t++)
        {
            for(int j= 0;j<p2;j++)
                ans+=t;
        }
        int ans_len=ans.length();
        if( p1==2 && isalpha(l) )
        {
            for(int i=0;i<ans_len;i++)
                ans[i] = ans[i]-'a'+'A';
        }
        if(p1==3)
        {
            for(int i=0;i<ans_len;i++)
                ans[i] = '*';
        }
        if(p3==2)
            reverse(ans.begin(),ans.end());
        return ans;
    }
    else return "-";
}

int main()
{
    int p1,p2,p3;
    cin >> p1 >> p2 >> p3;
    string s;
    cin >> s;

    string ans = "";

    int s_len = s.length();
    for(int i=0;i<s_len;i++)
    {
        //边界判断,wa10%
        if(s[i]=='-' && i+1<s_len && i-1>=0 )
            ans += get_char(s[i-1],s[i+1],p1,p2,p3);
        else
            ans += s[i];
    }

    cout << ans;
    return 0;
}
View Code

枚举

思路:合适的枚举对象、顺序、方法

合适的枚举顺序:

NC16593 [NOIP2011]铺地毯【逆向思维】

//思路,单点查询 => 倒序寻找

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

const int N=1e4+10;
int memory[N][4];

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<4;j++)
            cin>>memory[i][j];
    }

    int x,y;
    cin>>x>>y;

    for(int i=n;i>=1;i--)
    {
        //铺设地毯的左下角的坐标(a,b)以及地毯在x轴和y轴方向的长度。
        if(memory[i][0] <= x && memory[i][1] <= y )
            if(memory[i][0]+memory[i][2]-1 >= x && memory[i][1]+memory[i][3]-1 >= y )
            {
                printf("%d\n",i);
                return 0;
            }
    }

    printf("-1\n");
    return 0;
}
View Code

 

 

第二章: 递归、分治

递归:

NC15173 The Biggest Water Problem

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

long long get_sum(long long x)
{
    long long t=0;
    while(x)
    {
        t+=x%10;
        x/=10;
    }
    return t;
}

int main()
{
    long long a;
    long long sum=0;
    cin>>a;
    while(a>0)
    {
        sum = get_sum(a);
        if(sum < 10 )
        {
            printf("%lld",sum);
            return 0;
        }
        a=sum;
    }
    return 0;
}
View Code

分治:

NC16660 [NOIP2004]FBI树

// 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。
// FBI树是一种二叉树[1],它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
// 1) 根结点为R,其类型与串S的类型相同;
// 2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
// 现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历[2]序列。

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

const int N=1e5+10;//数组大小猜的
int rt;
struct node
{
    char v;
    int lc,rc;
}tree[N];
int tot;

string s;

char find(int l,int r)
{
    bool find_0=false,find_1=false;
    for(int i=l;i<=r;i++)
    {
        if(find_0 && find_1 ) 
            break;
        if(s[i] == '0')
            find_0=true;
        if(s[i] == '1')
            find_1=true;
    }
    
    if(find_0 && find_1 )
        return 'F';
    else if(find_0 )
        return 'B';
    else
        return 'I';
}

void build(int &root,int l,int r)
{
    root=tot++;
    tree[root].lc = tree[root].rc = -1;
    tree[root].v = find(l,r);

    if(l == r)
        return ;
    else
    {
        int mid = (l+r)>>1;
        build(tree[root].lc,l,mid);
        build(tree[root].rc,mid+1,r);
        return ;
    }
}

void post_order(int root)
{
    if(tree[root].lc !=-1)
        post_order(tree[root].lc);
    if(tree[root].rc !=-1)
        post_order(tree[root].rc);
    printf("%c",tree[root].v);
}

int main()
{
    int n; cin>>n;
    cin>>s;

    build(rt,0,s.length()-1);
    post_order(rt);

    return 0;
}
View Code

 

 

 

第三章: 二分、三分、01分数规划

二分:

二分查找:

NC235558 牛可乐和魔法封印

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

int n,q;
const int N=1e5+10;
int d[N];

int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>d[i];
    sort(d,d+n);

    cin>>q;
    while(q--)
    {
        int a,b;
        cin>>a>>b;
        //似乎不能使用L,R作为变量名,会出错
        int lpos= lower_bound(d,d+n,a)-d ;
        int rpos= upper_bound(d,d+n,b)-d ; 
        printf("%d\n",rpos-lpos);
    }

    return 0;
}
View Code

 

第四章: 栈、队列

栈:

NC14326 Rails

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

int n,q;
const int N=1e3+10;
int d[N];

stack <int > sta;

int main()
{
    int n;
    bool first = true;
    while(scanf("%d",&n) && n!=0 )
    {
        if(!first )
            printf("\n");
        while(scanf("%d",&d[0]) && d[0]!=0 )
        {
            if(!first )
                printf("\n");
            else first=false;

            while(!sta.empty() ) sta.pop();
            for(int i=1;i<n;i++)
                cin>>d[i];
            
            int nw=0,pos=1;
            bool fail=false;
            while(nw<n && !fail )
            {
                if(!sta.empty() && d[nw] == sta.top() )
                    sta.pop(),nw++;
                else if(d[nw] < pos )
                    fail=true;
                else if(d[nw] == pos )
                    nw++,pos++;
                else 
                    sta.push(pos++);
            }
            if(!fail )
                printf("Yes");
            else printf("No");
        }

    }

    return 0;
}
View Code

队列:

NC13822 Keep In Line

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

int T,n;
queue <int > q;

int tot;
map <string ,int > id; 

const int N=1e5+10;
bool out[N];

int main()
{
    int cnt=0;//不插队人数

    cin>>T;
    while(T--)
    {
        while(!q.empty() )
            q.pop();
        tot = 0;
        id.clear();
        cnt = 0; //这个不写wa一次...

        string s1,s2;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>s1>>s2;
            if(s1[0]=='i' )
            {
                id[s2] = ++tot;
                q.push(tot);
                cnt++;
                //cout << s2 << " "<<tot<<endl;
                //cout<<cnt<<endl;
            }
            else
            {
                if(q.front() != id[s2] )
                {
                    cnt--;
                    out[id[s2]]=true;
                }
                else
                {
                    q.pop();
                    while(!q.empty() && out[q.front()] )
                        q.pop();
                }
                //cout<<cnt<<endl;
            }
        }
        printf("%d\n",cnt);
        
        for(int i=1;i<=tot;i++)
            out[i]=false;
    }

    return 0;
}
View Code

 

 

第五章:优先队列、并查集

堆:

模板:

NC16663 合并果子

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

int main()
{
    priority_queue <int , vector <int > ,greater <int > > q;

    int n;
    cin >> n;
    for(int i=1,x;i<=n;i++)
        cin>>x,q.push(x);

    long long sum = 0;
    while(!q.empty() )
    {
        long long t = q.top(); q.pop();
        if(q.empty() ) break;
        
        t += q.top();
        q.pop();
        q.push(t);
        sum += t ;
    }
    
    cout<<sum;
    return 0;
}
View Code

NC214362 第k小

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

int n,m,k;
const int N=2e5+10;
//greater 改成小根堆
priority_queue <int ,vector <int > ,greater <int > > q1; //放置 k+1 到 n 的数字
priority_queue <int ,vector <int > ,less <int > > q2; //放置 1 到 k 的数字

void get(int x) //限制条件为,q2一定满了,q1中可能有数
{
    int cnt_sub = 0 ;
    if(q2.top() > x) //实际上x只会挤走一个q2中的数
    {
        q1.push(q2.top() );
        q2.pop();
        q2.push(x);
    }
    else
        q1.push(x);
}

int main()
{
    cin>>n>>m>>k;
    int nw_n=0;

    int v;
    for(int i=1;i<=n;i++)
    {
        cin>>v;
        nw_n ++;
        if(nw_n <= k ) q2.push(v);
        else get(v);
    }

    int op;
    while(m--)
    {
        cin>>op;
        if(op==1 )
        {
            cin>>v;
            nw_n++;
            if(nw_n <= k ) q2.push(v);
            else get(v);
        }
        else
        {
            if(nw_n < k )
                printf("-1\n");
            else 
                printf("%d\n",q2.top() );
        }
    }

    return 0;
}
View Code

 

 

第六章:搜索

DFS:

回溯思想:

NC15128 老子的全排列呢

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

bool us[10];
int d[10];

void dfs(int pos)
{
    if(pos >= 8 ) 
    {
        for(int i=0;i<8;i++)
        {
            if(i!=0)
                printf(" ");
            printf("%d",d[i]);
        }
        printf("\n");
        return ;
    }
    else
    {
        for(int i=1;i<=8;i++)
            if(!us[i])
            {
                d[pos] = i;
                us[i] = true;
                dfs(pos+1);
                us[i] = false;
            }
    }
}

int main()
{
    dfs(0);

    return 0;
}
View Code

BFS:

NC15136 迷宫

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

int n,m;
const int N=510;

struct node
{
    int x,y;
    bool key;
    int step;
};
queue <node > q;

int py[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int mp[N][N];
int step[N][N][2];
//0表示能走,1表示钥匙,-1表示墙壁,D表示门锁

int main()
{
    int sx,sy,ex,ey;

    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            char ch = getchar();
            while(ch!='W' && ch!='K' && ch!='S' && ch!='D' && ch!='E' && ch!='.')
                ch = getchar();
            if(ch == 'W' )
                mp[i][j]=-1;
            else if(ch == 'K' )
                mp[i][j]=1;
            else if(ch == 'D' )
                mp[i][j]=2;
            else if(ch == 'S')
                sx = i , sy = j;
            else if(ch == 'E' )
                ex = i , ey = j;
        }
    }

//     for(int i=1;i<=n;i++)
//     {
//         for(int j=1;j<=m;j++)
//         {
//             printf("%3d ",mp[i][j]);
//         }
//         printf("\n");
//     }
    //printf("%d %d \n",ex,ey);
    q.push({sx,sy,false,0});
    while(!q.empty() )
    {
        node t = q.front();
        q.pop();

        for(int i=0;i<4;i++)
        {
            int nx = t.x + py[i][0];
            int ny = t.y + py[i][1];

            if(nx<1 || ny<1 || nx>n || ny>m )
                continue;
            if(mp[nx][ny] == -1 )
                continue;
            if(mp[nx][ny] == 2 && !t.key )
                continue;
            
            bool t_key = t.key;
            if(mp[nx][ny] == 1 ) t_key = true;
            
            if(step[nx][ny][t_key]>0 ) continue;
            step[nx][ny][t_key] = t.step +1;
            //printf("%d %d %d %d\n",nx,ny,t_key,t.step+1);
            
            if(nx == ex && ny == ey )
            {
                printf("%d\n",t.step+1);
                return 0;
            }

            q.push({nx,ny,t_key,t.step+1});    
        }
    }
    printf("-1\n");
    return 0;
}
View Code

 

 

 

第七章:

递推:

NC235911 走楼梯

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

const int N=110;
int f[N];

int main()
{
    int n;
    cin>>n;

    f[0]=1,f[1]=1;
    for(int i=2;i<=n;i++)
        f[i] = f[i-1]+f[i-2];
    printf("%d\n",f[n]);
    return 0;
}
View Code

线性dp:

NC22096 数字三角形(什么算法也没用,很水)

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

int main()
{
    int n;
    while(~scanf("%d",&n) )
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(j!=1 )
                    printf(" ");
                printf("%d",j);
            } 
            printf("\n"); 
        }
    }
    return 0;
}
View Code

 

背包问题:

01背包:

NC16693 装箱问题

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

const int M=2e5+10;
bool f[M];

int main()
{
    int V,n;
    cin>>V>>n;
    
    f[0]=true;
    for(int i=1;i<=n;i++)
    {
        int v; cin>>v;
        for(int j=V;j>=v;j--)
        {
            if(f[j-v] )
                f[j]=true;
        }
    }
    for(int j=V;j>=0;j--)
        if(f[j] )
        {
            printf("%d",V-j);
            return 0;
        }
    return 0;
}
View Code

 

 

 

第八章:

树形dp:

【基本概念-笔记】:【笔记】树形dp - 心若笺诗 - 博客园 (cnblogs.com)

【基本算法-笔记】:【笔记】【树形dp】 - 心若笺诗 - 博客园 (cnblogs.com)

NC15033 小G有一个大树

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

const int N=1e3+10;
int n;
vector <int > son[N];
int point,num;

int f[N],sum[N];
//sum是x点子树的所有节点数,不包括自己
//f是去掉x,x点子树中节点最多的连通块

void dfs(int x,int fr)
{
    int sz=son[x].size();
    sum[x] = 1;

    for(int i=0;i<sz;i++)
    {
        int nx=son[x][i];
        if(nx==fr ) continue;

        dfs(nx,x);
        sum[x] += sum[nx];
    }
    for(int i=0;i<sz;i++)
    {
        int nx=son[x][i];
        if(nx==fr ) continue;

        f[x] = max(f[x],sum[nx]);
    }

    int t = max(f[x],n-sum[x]);
    if(t < num )
        num=t,point=x;
}

int main()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        son[u].push_back(v);
        son[v].push_back(u);
    }
    
    num=n;
    dfs(1,0);

    printf("%d %d",point,num);

    return 0;
}
View Code

 

第九章:

基本概念:

NC16679 [NOIP2003]神经网络

(本题简略题解:【图论】【刷题】【蓝绿题】【强连通】【拓扑】 - 心若笺诗 - 博客园 (cnblogs.com)

#include<cstdio>
#include<cstdlib>
#include<queue>
#include<vector>
using namespace std;
int n,m;
const int N=103;
int c[N],in[N],sz[N];
struct node
{
    int v,w;
    node(int vv,int ww)
    { v=vv,w=ww; }
    node(){}
};
vector <node > g[N];
queue <int > q;

void topo_sort()
{
    while(!q.empty())
    {
        int t=q.front();q.pop();
        sz[t]=g[t].size() ;
        
        for(int i=0;i<sz[t];i++)
        {
            node v=g[t][i];
            if(c[t]>0) c[v.v ]+=c[t]*v.w ;
            if(--in[v.v ]==0) q.push(v.v );
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&c[i],&x);
        if(c[i]>0) q.push(i);
        else c[i]-=x;
    }
    int u,v,w;
    while(m--)
    {
        scanf("%d%d%d",&u,&v,&w);
        g[u].push_back(node(v,w)); 
        in[v]++;
    }
    
    topo_sort();
    bool fail=true;
    for(int i=1;i<=n;i++)
        if(!sz[i] && c[i]>0)
        {
            printf("%d %d\n",i,c[i]);
            fail=false;
        }
    if(fail) printf("NULL\n");
    return 0;
}
View Code

NC20115 [HNOI2015]菜肴制作

(感觉还蛮有写头的,所以另开了篇题解)

 

 

第十章:

数论:

NC14399 素数判断

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

int T;

vector <int > v;
const int N=1e5;
bool notprime[N+10];
void prepare()
{
    for(int i=2;i<=N;i++)
        if(!notprime[i] )
        {
            v.push_back(i);
            for(int j=2;i*j<=N;j++)
                notprime[i*j]=true;
        }
}

int sz;

bool check (int x)
{
    for(int i=0;i<sz && v[i]<x ;i++)
        if(x%v[i] == 0 ) return false;
    return true;
}

int main()
{
    prepare(); //1e5范围内的素数都取出来
    sz = v.size();

    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        
        if(check(n) )
        {
            printf("isprime\n");
            printf("%d\n",n);
        }
        else
        {
            printf("noprime\n");
            bool first = true;
            for(int i=0; i<sz && v[i]<=n ;i++)
            {
                if(n%v[i] == 0 )
                {
                    if(first )
                        first = false;
                    else printf(" ");
                    
                    printf("%d",v[i]);
                    while(n % v[i] == 0 ) 
                        n/=v[i];
                }
            }
            //因为下面这句话我wa了4个点...
            if(n != 1 )
                printf(" %d",n);
            //比如p>1e5且p是素数,原来算法对于2p,不会输出p
            printf("\n");
        }
    }
    
    return 0;
}
View Code

 

第十一章:

线段树:

NC15164 Big Water Problem

【代码1】树状数组模板

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

int n;
const int N = 1e5 + 10;
int a[N], c[N];
// a[i]为原始数组
// c[i]为树状数组

int lowbit(int x)
{
    return x & -x;
}

void build() //利用a[i]数组数据建立c[i]
{
    for (int i = 1; i <= n; i++)
    {
        c[i] = a[i];
        int k = i - lowbit(i) + 1;
        for (int j = k; j < i; j++)
            c[i] += a[j];
    }
}

int sum(int x)
{
    int sum = 0;
    while (x > 0)
    {
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}

int query_sum(int l, int r)
{
    return sum(r) - sum(l - 1);
}

void add(int pos, int x)
{
    while (pos <= n)
    {
        c[pos] += x;
        pos += lowbit(pos);
    }
}

int main()
{
    int m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    build();

    int op, a, b;
    while (m--)
    {
        cin >> op >> a >> b;
        if (op == 1)
            add(a, b);
        else
            cout << query_sum(a, b)<<endl;
    }

    return 0;
}
View Code

【代码2】线段树模板

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

int n;
const int N = 1e5 + 10;
int d[N];
int rt, tot;

struct node
{
    int l, r;   //区间[l,r]
    int lc, rc; //左右子节点
    int v;      //区间整体的值
} tree[N * 3];

void push_up(int x)
{
    tree[x].v = 0;
    if (tree[x].lc != -1)
        tree[x].v += tree[tree[x].lc].v;
    if (tree[x].rc != -1)
        tree[x].v += tree[tree[x].rc].v;
    return;
}

void create(int &root, int l, int r)
{
    if (l > r)
        return;
    root = tot++;
    tree[root].l = l, tree[root].r = r;

    if (l == r)
    {
        tree[root].lc = tree[root].rc = -1;
        tree[root].v = d[l];
    }
    else
    {
        int mid = (l + r) >> 1;
        create(tree[root].lc, l, mid);
        create(tree[root].rc, mid + 1, r);
        push_up(root);
    }
}

void change(int root, int pos, int v) //单点修改
{
    if (tree[root].l == tree[root].r)
        tree[root].v = v;
    else
    {
        int mid = (tree[root].l + tree[root].r) >> 1;
        if (pos <= mid)
            change(tree[root].lc, pos, v);
        else
            change(tree[root].rc, pos, v);
        push_up(root);
    }
}

int query(int root, int l, int r) //当前查找的节点为root,l,r为需要查找的区间看两者是否符合
{
    if (l <= tree[root].l && tree[root].r <= r)
        return tree[root].v;
    else
    {
        int mid = (tree[root].l + tree[root].r) >> 1, sum = 0;
        if (l <= mid)
            sum += query(tree[root].lc, l, r);
        if (r > mid)
            sum += query(tree[root].rc, l, r);
        return sum;
    }
}

int main()
{
    int m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> d[i];

    create(rt, 1, n);

    while (m--)
    {
        int op, a, b;
        cin >> op >> a >> b;
        if (op == 1)
        {
            d[a]+=b;
            change(rt, a, d[a]);
        }
        else
            cout << query(rt, a, b) << endl;
    }

    return 0;
}
View Code

 

第十二章:

LCA模板题

DFS序:

NC13611 树(dfs序+区间dp)

做不倒,现学数论在补了已经呜呜

 

 

 

posted @ 2022-07-11 16:44  心若笺诗  阅读(72)  评论(0编辑  收藏  举报