团队设计天梯赛L2题解集

前言

在刷L2的过程中,深感基础之薄弱,特写此博客总结。

L2-001 紧急救援

题意:求最短路径的条数,在最短的路径中找出一条结点合最大的,并且输出路径。
思路: dijkstra算法,sum[i]是存的当前节点到根节点最小路径数目,num[i]存的当前结点到根节点的最大节点和。每次松弛操作如果d[v]>d[x]+w 就更新最小路径数目 sum[v]=sum[x]; nums[v]+=o[x];并记录路径. 如果d[v]==d[x]+w就说明找到了另一条最小路径故sum[v]+=sum[x],再判断结点合是不是最大的if(num[v]<num[x]+o[v])
不是的话就更新。

view code
#include <bits/stdc++.h>
using namespace std;
const int maxn=505;
const int maxm=250000+5;
const int INF=0x3f3f3f3f;
struct E
{
    int to,w,next;
} edge[maxm];

int head[maxn],vis[maxn],d[maxn],sum[maxn],num[maxn],path[maxn],o[maxn];
int n,m,S,D;
int tot=1;
void AddEdge(int u,int v,int w)
{
    edge[tot].w=w;
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
priority_queue<pair<int,int> > q;
void dijikstra()
{
    for(int i=0; i<=n; i++) d[i]=INF,vis[i]=0;
    d[S]=0;
    sum[S]=1;
    q.push(make_pair(0,S));
    while(q.size())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=1;

        for(int i=head[x]; i; i=edge[i].next)
        {
            int v=edge[i].to,w=edge[i].w;
            if(d[v]>d[x]+w)
            {
                d[v]=d[x]+w;
                sum[v]=sum[x];
                num[v]=num[x]+o[v];
                path[v]=x;
                q.push(make_pair(-d[v],v)); //填入负数,因为优先队列默认排大的数
            }
            else if(d[v]==d[x]+w){
                sum[v]+=sum[x];
                if(num[v]<num[x]+o[v]){
                    num[v]=num[x]+o[v];
                    path[v]=x;
                }
    }
}
int c[maxn];
void print(){
    int pre=path[D];
    int tot=0;
    while(pre!=-1){
        c[tot++]=pre;
        pre=path[pre];
    }
    while(tot--){
        cout<<c[tot]<<" ";
            }
        }
    }
    cout<<D;
}
int main()
{
    cin>>n>>m>>S>>D;
    path[S]=-1;
    for(int i=0;i<n;i++) cin>>num[i],o[i]=num[i];
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        AddEdge(u,v,w);
        AddEdge(v,u,w);
    }
    dijikstra();
    printf("%d %d\n",sum[D],num[D]);
    print();
    return 0;
}

L2-002 链表去重

思路: 看了网上一个大佬的思路,给结点定义一个num 用来表示链表时链表从头到尾的编号,当遇到重复的键值结点时,便让编号+n,这样就可省去对地址删改的操作。
然后按num大小排序,即可按链表的顺序输出。

view code
#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int maxm=1e7+5;
const int INF=0x3f3f3f3f;


struct node{
    int address,key,next,num;
}a[maxn];

bool cmp(node a,node b){
    return a.num<b.num;
}
bool vis[maxn];
int head,n;

int main()
{

    cin>>head>>n;
    for(int i=0;i<maxn;i++) a[i].num=INF;

    for(int i=0;i<n;i++){
        int x;cin>>x;
        cin>>a[x].key>>a[x].next;
        a[x].address=x;
    }
    int num1=0,num2=0;
    for(int i=head;i!=-1;i=a[i].next){
            if( !vis[abs(a[i].key)] ){
                vis[abs(a[i].key)]=true;
                a[i].num=num1++;
            }
            else{
                a[i].num=1+n+num2; num2++;
            }
    }
    sort(a,a+maxn,cmp);
    int num3=num1+num2;
    for(int i=0;i<num3;i++){
        if(i!=num1-1&&i!=num3-1){
             printf("%05d %d %05d\n",a[i].address,a[i].key,a[i+1].address);
        }else{
            printf("%05d %d -1\n",a[i].address,a[i].key);
        }

    }

    return 0;
}

L2-003 月饼

思路:模拟,按价值高的排序,然后判断库存是否大于需求

view code
#include<bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

struct node{
    double p,r;
}a[maxn];
bool cmp(node a,node b){
    return a.p>b.p;
}
int n,w;
int main()
{
    cin>>n>>w;
    for(int i=0;i<n;i++) cin>>a[i].r;
    for(int i=0;i<n;i++){
        double x;cin>>x;
        a[i].p=x/a[i].r*1.00;
    }
    sort(a,a+n,cmp);
    double ans=0;
    for(int i=0;i<n;i++){
        if(w>=a[i].r){
            w-=a[i].r;
            ans+=a[i].r*a[i].p;
        }
        else{
            ans+=w*a[i].p;
            w=0;
        }
        if(w==0) break;

    }
    printf("%.2lf",ans);
    return 0;
}

L2-004 这是二叉搜索树吗?

思路: 被这个题目搞的头疼,自己写的程序有个测试点一直爆栈(递归用的太多),然后叕叕看了大佬的写法。
具体思路不难想,要判断两次(非镜像和镜像),然后分情况建树,输出。难点在于优化,判断和建树程序的优化。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e3+5;

int a[maxn];
int n;

struct node{
    int val;
    node *left;
    node *right;
    node(int v,node *l,node *r){
        val=v; left=l;right=r;
    }
};
node *root=NULL;
int isBST(int i,int j){

    if(i>=j) return 1;
    int p=j;
       for(int k=i+1;k<=j;k++){
            if(a[k]>=a[i]){
                p=k;break;
            }
   }
     for(int z=p+1;z<=j;z++){
        if(a[z]<a[i]) return 0;
    }
    return isBST(i+1,p-1)&&isBST(p,j);
}

int isBST2(int i, int j){
    if(i>=j) return 1;
     int p=j;
   for(int k=i+1;k<=j;k++){
        if(a[k]<a[i]){
                p=k;break;
            }
   }
    for(int z=p+1;z<=j;z++){
        if(a[z]>=a[i]) return 0;
   }
    return isBST2(i+1,p-1)&&isBST2(p,j);
}
//普通递归建树,有个测试点会栈溢出
node *build1(int i,int j){

    if(i==j) return new node(a[i],NULL,NULL);
    if(i>j) return NULL;
    int p=i+1;
    while(a[p]<a[i]) p++;
    return new node(a[i], build1(i+1,p-1),  build1(p,j));
}
//镜像
node *build2(int i,int j){

    if(i==j) return new node(a[i],NULL,NULL);
    if(i>j) return NULL;
    int p=i+1;
    while(a[p]>=a[i]) p++;
    return new node(a[i], build2(i+1,p-1), build2(p,j));

}
// 优化的建树方法
node *build3(node *t,int key){
        if(t==NULL){ return new node(key,NULL,NULL);}
        if(key>=t->val) t->right=build3(t->right,key);
        else t->left=build3(t->left,key);
        return t;
}
// 镜像
node *build4(node *t,int key){
        if(t==NULL){ return new node(key,NULL,NULL);}
        if(key<t->val) t->right=build4(t->right,key);
        else t->left=build4(t->left,key);
        return t;
}
static int sum=0;
void print(node *root){

    if(root==NULL) return;
    print(root->left);
    print(root->right);
    if(sum++!=0) printf(" ");
    printf("%d",root->val);
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    if(isBST(0,n-1)){
    printf("YES\n");
        for(int i=0;i<n;i++)
        root=build3(root,a[i]);
    print(root);
    }
    else if(isBST2(0,n-1)){
      printf("YES\n");
            for(int i=0;i<n;i++)
            root=build4(root,a[i]);
      print(root);
    }
    else{
        printf("NO\n");
    }
    return 0;
}


L2-005 集合相似度

思路:两个集合交集元素的个数/(两个集合元素的个数-交集元素个数) ,set存放即可

view code
#include<bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int INF=0x3f3f3f3f;

set<int> s[maxn];

int n,k;

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        int m; cin>>m;
        while(m--){
            int x; cin>>x;
            s[i].insert(x);
        }
    }
    cin>>k;
    while(k--){
        int a,b;
        cin>>a>>b;
        int num=0;
        for(int x:s[a]){
            if(s[b].count(x)) ++num;
        }
        double ans= 1.00*num/(s[a].size()+s[b].size()-num);
        printf("%.2lf%\n",ans*100);

    }
    return 0;
}

L2-006 树的遍历

题意:给定一棵树的后序和中序,输出层序遍历。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=35;
struct node{
    int left,right;
}a[maxn];

int m[maxn],b[maxn];

int build(int ml,int mr, int bl, int br){
    if(ml>mr){
        return -1;
    }
    int root=b[br],index=ml,num=0;
    while(m[index]!= b[br])index++;
    num=index-ml;
    a[root].left=build(ml,index-1,bl,bl+num-1);
    a[root].right=build(index+1,mr,bl+num,br-1);
    return root;

}
queue<int> q;
int flag=0;
void bfs(int root){
    q.push(root);
    while(q.size()>0){

    int len=q.size();
    while(len--){
        int x=q.front(); q.pop();
       if(flag++==0) cout<<x;
       else cout<<" "<<x;
        if(a[x].left!=-1) q.push(a[x].left);
        if(a[x].right!=-1) q.push(a[x].right);

      }
    }

}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>b[i];
    for(int i=0;i<n;i++) cin>>m[i];
    build(0,n-1,0,n-1);
    int root=b[n-1];
    bfs(root);
    return 0;
}

L2-007 家庭房产

思路:并查集,不会。叕学习了下大佬的代码。题意要求以家庭中编号最小的成员代表这个家庭,故在并查集merge操作中,每次合并让编号小的作父节点,并更新值。
用set存放出现过的人,保证遍历找每个家庭代表时不会重复。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

int f[maxn],pnum[maxn];
int n;
set<int> s;
int id,fa,mo,k,child;

double fn,fc,fnum[maxn],fcover[maxn];
//fn:房产数量,fc:房产面积 fnum[] 存放每个结点的房产数量,fcover[]每个结点的房产数量

void init(){
    for(int i=0;i<10005;i++){
            f[i]=i;
            pnum[i]=1;//家庭人口数初始为1
    }
}
int found(int x){
  return x==f[x]?x:f[x]=found(f[x]);
}
int merg(int x,int y){
        int fx=found(x),fy=found(y);
        if(fx!=fy){
            if(fx<fy) swap(fx,fy);
            pnum[fy]+=pnum[fx];
            fnum[fy]+=fnum[fx];
            fcover[fy]+=fcover[fx];
            f[fx]=fy;
        }
    return fy;
}
bool cmp(int a,int b){
    if(fcover[a]==fcover[b]) return a<b;
    return fcover[a]>fcover[b];
}
vector<int> ans;
int main()
{
    init();
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>id>>fa>>mo>>k;
        s.insert(id);
       if(fa!=-1){
            s.insert(fa);
            id=merg(id,fa);
        }
        if(mo!=-1){
            s.insert(mo);
            id=merg(id,mo);
        }
        while(k--){
            cin >> child;
            s.insert(child);
            id = merg(id,child);
        }
        cin >> fn >> fc;
       fnum[id] += fn;
        fcover[id] += fc;
    }

    for(set<int>::iterator it=s.begin(); it!=s.end(); it++){
        if(f[*it]==*it){
            fnum[*it]/=pnum[*it];
            fcover[*it] /= pnum[*it];
            ans.push_back(*it);
        }
    }
    sort(ans.begin(),ans.end(),cmp);
    cout<<ans.size()<<endl;
    for(vector<int>::iterator it = ans.begin();it != ans.end();it ++) {
        printf("%04d %d %.3f %.3f\n",*it,pnum[*it],fnum[*it],fcover[*it]);
    }
    return 0;
}

L2-008 最长对称子串

思路: 一开始以为是dp,结果没搞出来。看了题解暴力遍历即可.

view code
#include <iostream>
using namespace std;
int main() {
    string s;
    getline(cin, s);
    int maxvalue = 0, temp;
    int len = s.length();
    for(int i = 0; i < len; i++) {
        temp = 1;
        for(int j = 1; j < len; j++) {
            if(i - j < 0 || i + j >= len || s[i - j] != s[i + j])
                break;
            temp += 2;
        }
        maxvalue = temp > maxvalue ? temp : maxvalue;
        temp = 0;
        for(int j = 1; j < len; j++) {
            if(i - j + 1 < 0 || i + j >= len || s[i - j + 1] != s[i + j])
                break;
            temp += 2;
        }
        maxvalue = temp > maxvalue ? temp : maxvalue;
    }
    cout << maxvalue;
    return 0;
}

L2-009 抢红包

思路: 模拟排序即可

view code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e4+5;

struct node{
   int id;
   int hb;
   double num;

}a[maxn];

bool cmp(node a,node b){

    if(a.num==b.num){
        if(a.hb==b.hb) return a.id<b.id;
        return a.hb>b.hb;
    }
    return a.num>b.num;
}

int main()
{
    int N;
   scanf("%d",&N);
    for(int i=0;i<N;i++){ a[i].num=0.00,a[i].id=i;     }

    for(int i=0;i<N;i++){
        int k;
      scanf("%d",&k);
        while(k--){
            int x;
            scanf("%d",&x);
            int y; scanf("%d",&y);
            a[x-1].num+=y;
            a[x-1].hb++;
            a[i].num-=y;
        }
    }
    sort(a,a+N,cmp);
    for(int i=0;i<N;i++){
        printf("%d %.2lf\n",a[i].id+1,a[i].num/100);
    }
    return 0;
}

L2-010 排座位

思路: 二维数组建图存关系,可能存在 A是B朋友,B是C朋友,C是D朋友,所以A和D是朋友这种情况,所以用并查集判断两人是否是朋友。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e2+5;
const int inf=0x3f3f3f3f;

int edge[105][105];
int f[105];
int found(int x){
    if(x==f[x]){
        return x;
    }
    return f[x]=found(f[x]);
}
void uion(int a,int b){
    int t1=found(a),t2=found(b);
    if(t1!=t2) f[t1]=t2;
}
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    memset(edge,inf,sizeof(edge));
    for(int i=1;i<=n;i++) f[i]=i;
    while(m--){
    int u,v,w; cin>>u>>v>>w;
    if(w==1)
    uion(u,v);
    edge[u][v]=w;
    edge[v][u]=w;

    }
    while(k--){
        int x,y;
        cin>>x>>y;
        if(edge[x][y]==inf) cout<<"OK\n";
        else{
                int flag=0;
                if(found(x)==found(y)&&edge[x][y]==-1) {cout<<"OK but...\n";flag=1;}
                if(!flag){
                    if(edge[x][y]==1) cout<<"No problem\n";
                    else cout<<"No way\n";

                }
        }

    }
    return 0;
}

L2-011 玩转二叉树

题意: 给定先序和中序建立二叉树,然后层序遍历的时候,每层倒着输出。和第六题中序,后序建树差不多。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=35;

struct Node{
    int left,right;
}node[maxn];

int n;
int a[maxn];
int b[maxn];

int build(int la,int ra,int lb,int rb){
            if(lb>rb) return 0;
            if(lb==rb) return b[lb];
            int root=b[lb];
            int index=la;
            for(;index<=ra;index++){
            if(a[index]==root)break;
        }
           int  num=index-la;
            node[root].left=build(la,index-1,lb+1,lb+num);  //注意这里不是num-1了
            node[root].right=build(index+1,ra,lb+num+1,rb);
            return root;
}
queue<int> q;
stack<int> ans;
int flag=0;
void bfs(int root){
    if(root!=0)
    q.push(root);
    while(q.size()>0){
        int len=q.size();

        while(len--){
        int x=q.front(); q.pop();
           if(node[x].left!=0)q.push(node[x].left);
           if(node[x].right!=0) q.push(node[x].right);
            ans.push(x);
        }
        while(ans.size()!=0) {
            if(flag!=0)
            cout<<" "<<ans.top();
            else
            cout<<ans.top();
            ans.pop();
            flag++;
        }

    }

}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<n;i++)cin>>b[i];
    int root=build(0,n-1,0,n-1);
    bfs(root);
    return 0;
}

L2-012 关于堆的判断

思路:小根堆,完全二叉树且子节点不得小于父节点。 因为是完全二叉树我们从编号1开始计数, 编号为i的结点子节点为2i和2i+1,父节点为i/2;
建树:每次添加结点,要判断是否大于父节点,如果不是,就交换子父结点,循环地判断直到父节点为根节点时。
查询:在一维数组里遍历树,返回结点下标。注意:因为层数可能不同,两个下标中较小的那个如果为奇数则一定不是兄弟结点。

view code
#include <iostream>

using namespace std;
const int maxn=1e3+5;

int h[maxn];
int n,m;

void update(int i){
    if(i==1) return;
    while(i>1){
        if(h[i]<h[i/2]){
            swap(h[i],h[i/2]);
            i/=2;
        }
        else return;
    }
}

void findp(int a,int b,int &ap,int &bp){
        for(int i=1;i<=n;i++){
            if(h[i]==a) ap=i;
            else if(h[i]==b) bp=i;
        }
}
int main()
{
    string s;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>h[i];update(i);
    }
    for(int i = 0;i<m;++i){
        int a,b;
        int ap,bp;
        cin>>a;
        cin>>s;
        if(s=="and"){///兄弟
            cin >> b;
            getline(cin,s);
            findp(a,b,ap,bp);
            if(ap>bp) swap(ap,bp);
            if(ap%2==0 && bp-ap == 1 ) cout<<"T"<<endl;
            else cout<<"F"<<endl;
        }
        else{
            cin>>s;
            if(s=="a"){///a 是 b 孩子
                cin>>s;cin>>s>>b;
                findp(a,b,ap,bp);
                if(ap/2 == bp) cout<<"T"<<endl;
                else cout<<"F"<<endl;
            }
            else{
                cin>>s;
                if(s=="root"){///根
                    if(h[1]==a) cout<<"T"<<endl;
                    else cout<<"F"<<endl;
                }
                else{///a 是 b父亲
                    cin>>s>>b;
                    findp(a,b,ap,bp);
                    if(bp/2 == ap) cout<<"T"<<endl;
                    else cout<<"F"<<endl;
                }
            }
        }
    }
    return 0;
}

L2-013 红色警报

太菜了,一开始竟想到图论去了。叕学习了大佬们的博客
题意:找连通块,去掉一个结点后如果图中连通块的数量减少则发出警报
思路:两次dfs寻找连通块,找连通块:对每个结点都判断一下是否访问过,以及是否存在。
先dfs找不去除一个结点的连通块数,随后p[x]=1;代表去除结点,再找去除结点后的连通块数。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=505;
const int maxm=5005;
const int inf=0x3f3f3f;
int n,m;
struct E{
    int to,next;
}edge[maxm*2];

int head[505],vis[505],p[505];
int tot=1;
void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;

}

void dfs(int x){
    vis[x]=1;
    for(int i=head[x]; i!=0; i=edge[i].next){
            int v=edge[i].to;
            if(vis[v]||p[v]) continue;
            vis[v]=1;
            dfs(v);
    }

}
int main()
{
    scanf("%d %d",&n,&m);
    while(m--){
        int u,v;
        scanf("%d %d",&u,&v);
        AddEdge(u,v); AddEdge(v,u);

    }
    int k;scanf("%d",&k);
    int sum=0;
    while(k--){
         memset(vis,0,sizeof(vis));
        int x;scanf("%d",&x);
        sum++;
        int cnt1=0,cnt2=0;
        for(int i=0;i<n;i++){
            if(!vis[i] && !p[i] ){
                cnt1++;dfs(i);
            }

        }
        p[x]=1;
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            if(!vis[i] && !p[i]){
                cnt2++; dfs(i);
            }

        }

        if(cnt2-cnt1>0)
        printf("Red Alert: City %d is lost!\n",x);
        else
        printf( "City %d is lost.\n",x);
        if(sum==n) printf("Game Over.");
    }
    return 0;
}

L2-014 列车调度

思路: 求最大能划分的下降序列的个数 == 求最长上升子序列的长度

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;

int dp[maxn];
int pos[maxn];
int main()
{
    int n; scanf("%d ",&n);

    int len=0;
    int ans=0;
    while(n--){
        int a; scanf("%d",&a);
        if(len==0||a>dp[len]) dp[++len]=a;
        else{
            int l=upper_bound(dp+1,dp+len+1,a)-dp;
            dp[l]=a;
        }
    }
    cout<<len;
    return 0;
}

L2-015 互评成绩

思路: 模拟即可,用了优先队列弹出成绩前M高的数。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;

priority_queue<double> q;
double ans[maxn];
int main()
{
    int k,m,n;
    scanf("%d %d %d",&k,&m,&n);
    for(int i=0;i<k;i++){
            double mmax=-1.00,mmin=500.00;
            double sum=0;
        for(int j=0;j<m;j++){
                double x;scanf("%lf",&x);
                mmax=max(x,mmax);
                mmin=min(x,mmin);
                sum+=x;
        }
        sum-=mmax+mmin;
        double num=1.000*sum/(m-2);
        q.push(num);
    }
    int c=0;
    while(n--){
        ans[c++]=q.top();
        q.pop();

    }
    for(int i=c-1;i>=0;i--){
            if(i==0)
         printf("%.3lf",ans[i]);
            else
            printf("%.3lf ",ans[i]);
    }
    return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹

思路: 两次搜索,第一次把五代以内的结点全部标记一遍,第二次如果访问到了就说明不能结婚

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

map<int,int> f,m,vis,s;

int n;
int id,fa,ma;
string sex;

bool check(int a,int b){
    vis.clear();
    queue<int> q;
    q.push(a);
    int height=1;
    while(q.size()>0&&height<=5){
        int len=q.size();
        while(len--){
         int x=q.front();q.pop();
            if(f[x]!=0) q.push(f[x]);
            if(m[x]!=0) q.push(m[x]);
            vis[x]=1;
        }
        height++;
    }
    q.push(b);
    height=1;
    while(q.size()>0&&height<=5){
         int len=q.size();
         while(len--){
         int x=q.front();q.pop();
            if(vis[x]==1) return false;
            if(f[x]!=0) q.push(f[x]);
            if(m[x]!=0) q.push(m[x]);
            vis[x]=1;
        }
        height++;
    }

    return true;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    while(n--){
     cin>>id>>sex>>fa>>ma;
    if(sex[0]=='F') s[id]=1;
    else s[id]=2;
     if(fa!=-1)s[fa]=2,f[id]=fa;

     if(ma!=-1)s[ma]=1,m[id]=ma;

    }
    int k;cin>>k;
    while(k--){
    int a,b; cin>>a>>b;
    if(s[a]==s[b]) cout<<"Never Mind\n";
    else if(check(a,b)) cout<<"Yes\n";
    else cout<<"No\n";

    }
    return 0;
}

L2-017 人以群分

思路:前缀和维护总活跃度,排序,n是偶数对半分,n是奇数,两种情况分别判断下哪个多就完事。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;

long long sum[maxn];
int a[maxn];
int main()
{
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    sort(a,a+n);

    sum[0]=a[0];
    for(int i=1;i<n;i++){
        sum[i]+=sum[i-1]+a[i];
    }
    int n1,n2;
    long long ans=0;
    if(n%2==0) { n1=n2=n/2; ans=sum[n-1]-2*sum[n/2-1];}
    else{

          if(sum[n-1]-2*sum[n/2-1]>=sum[n-1]-2*sum[n/2]){
                    n1=n/2;n2=n-n1;
                    ans=sum[n-1]-2*sum[n/2-1];
          }
          else{
                n1=n/2+1;n2=n-n1;
                ans=sum[n-1]-2*sum[n/2];
          }

    }
    printf("Outgoing #: %d\n",n2);
    printf("Introverted #: %d\n",n1);
    printf("Diff = %lld\n",ans);

    return 0;
}

L2-019 悄悄关注

思路:模拟即可

view code
#include <bits/stdc++.h>
#include <string>
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
unordered_set<string> s;
vector <string> ans;
string a[maxn];
int b[maxn];
int main()
{
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n;
    for(int i=0;i<n;i++){
        string t;cin>>t;
        s.insert(t);
    }
    cin>>m;
    double sum=0;
    for(int i=0;i<m;i++){
        cin>>a[i];
       cin>>b[i];
         sum+=b[i];
    }
    double ave=sum/=m;

    for(int i=0;i<m;i++){
        if(b[i]>ave&&s.find(a[i])==s.end()){
                    ans.push_back(a[i]);
        }
    }
    sort(ans.begin(),ans.end());
    for(string i:ans){
       cout<<i<<endl;
    }
    if(ans.size()==0)
        cout<<"Bing Mei You";
    return 0;
}

L2-020 功夫传人

思路: 链式前向星存图,然后按照层序遍历的思路就ok了

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
const int maxm=1e5+5;

struct E{
    int to,next;
}edge[maxn<<1];

int head[maxn],a[maxn];
int tot=0;

void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}

queue<int> q;

int main()
{
    ios::sync_with_stdio(false);
    memset(head,-1,sizeof(head));
    int n; double z,r;
    cin>>n>>z>>r;
    for(int i=0;i<n;i++){
        int k; cin>>k;
        if(k==0) cin>>a[i];
        else
        while(k--){
            int v;cin>>v;
            AddEdge(i,v);
        }
    }
    q.push(0);

    double sum=0,cnt=1.00;
    r*=0.01;
    while(q.size()>0){
        int saize=q.size();
        while(saize-->0){
            int x=q.front(); q.pop();
            if(head[x]==-1){
                sum+=a[x]*cnt;continue;
            }
            for(int i=head[x];i!=-1;i=edge[i].next){
                int v=edge[i].to;
                q.push(v);
            }
        }
        cnt*=(1-r);
    }
    int ans=(int)(sum*z);
    cout<<ans;
    return 0;
}

L2-021 点赞狂魔

思路: 模拟排序即可

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;

struct node{
    string name;
    int len,ave;

}a[maxn];

bool cmp(node a,node b){
    if(a.len==b.len){
        return a.ave<b.ave;
    }
    return a.len>b.len;
}
int main()
{
        ios::sync_with_stdio(false);
        int n;
        cin>>n;
        for(int i=0;i<n;i++){
            cin>>a[i].name;
            int k;cin>>k;
            set<int> s;
            a[i].ave=k;
            while(k--){
                int x;cin>>x;
                s.insert(x);
            }
          a[i].len=s.size();
        }
        sort(a,a+n,cmp);
        if(n<3)
        for(int i=0;i<3;i++){
                if(i!=0) cout<<" ";
                if(i<n)
               cout<<a[i].name;
                else cout<<"-";
        }
        else
          for(int i=0;i<3;i++){
                if(i!=0) cout<<" ";
                cout<<a[i].name;
        }
        return 0;
}

L2-022 重排链表

思路有点混乱,对于这种链表的题目,一时间总是搞不清楚该怎样存链表,无奈又看了题解,真菜。
思路: 结构体存放输入数据,先用一个数组表示这条链表 s[0],s[1]依次代表链表的顺序,再定义一个数组,从开头和结尾向中间循环。

view code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 1e5+50;
int s[maxn],s1[maxn];
struct P{
    int x,y;
}a[maxn];
int main()
{
    int add,d,n,xx,t,j=0;
    scanf("%d %d",&xx,&t);
    for(int i=0;i<t;i++)
    {
        scanf("%d %d %d",&add,&d,&n);
        a[add].x = d;
        a[add].y = n;
    }
    while(xx!=-1){
        s[j++] = xx;
        xx = a[xx].y;
    }
    int l=0,r=j-1,q=0;
    while(l<=r){
        if(l==r) s1[q++] = s[l++];
        else{
            s1[q++] = s[r--];
            s1[q++] = s[l++];
        }
    }
    for(int i=0;i<j-1;i++)
        printf("%05d %d %05d\n",s1[i],a[s1[i]].x,s1[i+1]);
    printf("%05d %d -1\n",s1[j-1],a[s1[j-1]].x);
    return 0;
}

L2-023 图着色问题

思路: 链式前向星存边,判断每个结点,有个坑点是颜色一定要完全相等才算一个解。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=505;
const int maxm=250000+5;
struct E{
    int to,next;
}edge[maxm];

int head[maxn],judge[maxn];

int n,m,k;
int tot=0;
void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
set<int> s;
int main()
{
    ios::sync_with_stdio(false);

    cin>>n>>m>>k;
    while(m--){
        int u,v;cin>>u>>v;
        AddEdge(u,v); AddEdge(v,u);
    }
    int T; cin>>T;
    while(T--){
    s.clear();
    for(int i=1;i<=n;i++){
        cin>>judge[i];
        s.insert(judge[i]);
    }
    int len=s.size();
    if(len!=k){cout<<"No\n";continue;}
    int flag=0;
    for(int i=1;i<=n;i++){

        for(int j=head[i];j!=0;j=edge[j].next){
                int v=edge[j].to;
                if(judge[i]==judge[v]){flag=1;break;}

        }
        if(flag) break;
    }
    if(!flag)cout<<"Yes\n";
    else cout<<"No\n";

    }
    return 0;
}

L2-024 部落

思路:并查集

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

int f[maxn];

int find(int x){
    return x==f[x]? x:f[x]=find(f[x]);
}
void merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx!=fy){
        f[fx]=fy;
    }
}
set<int> s;
int main()
{
    ios::sync_with_stdio(false);
    int n; cin>>n;
    for(int i=1;i<=10000;i++){
        f[i]=i;
    }
    while(n--){
        int m; cin>>m;
        int pre;
        for(int i=0;i<m;i++){
            int x;cin>>x;s.insert(x);
            if(i==0) {pre=x; continue;}
            merge(pre,x);

        }
    }
    int sum=0;
    int slen=s.size();
    for(int i=1;i<=slen;i++){
            if(f[i]==i) sum++;
    }
    cout<<slen<<" "<<sum<<endl;
    int T;cin>>T;
    while(T--){
        int a,b; cin>>a>>b;
        if(find(a)==find(b)){
        cout<<"Y\n";
        }
        else
        cout<<"N\n";
    }
    return 0;
}

L2-025 分而治之

思路: dfs求连通块,和红色警报那题差不多

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=2e4+50;
struct E{
    int to,next;
}edge[maxn];

int head[maxn],vis[maxn],p[maxn];
int tot=0;
void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void dfs(int x){
       vis[x]=1;
    for(int i=head[x];i!=0;i=edge[i].next){
        int v=edge[i].to;
          if(vis[v]||p[v]) continue;
           vis[v]=1;
           dfs(v);
    }
}

int n,m,k;
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    while(m--){
        int u,v; cin>>u>>v;
        AddEdge(u,v); AddEdge(v,u);
    }
    cin>>k;
    while(k--){
        memset(vis,0,sizeof(vis));
        memset(p,0,sizeof(p));

        int np; cin>>np;
        for(int i=0;i<np;i++){
            int x; cin>>x;
            p[x]=1;
        }
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(!vis[i]&&!p[i]){
                cnt++;dfs(i);
            }
        }
        if(cnt==n-np)cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}

L2-026 小字辈

思路: 链式前向星存图,层序遍历记录最深层的结点

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
struct E{
    int to,next;
}edge[maxn];


int head[maxn];
int tot=0;
void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
queue<int> q;

vector<int> ans;

int main()
{
    ios::sync_with_stdio(false);
    memset(head,-1,sizeof(head));
    int n;cin>>n;
    int root=0;
    for(int i=1;i<=n;i++){
        int x;cin>>x;
        if(x!=-1)
        AddEdge(x,i);
        else
         root=i;
    }
    q.push(root);
    int cnt=1;
    while(q.size()>0){
        int len=q.size();
        ans.clear();
        while(len--){
             int x=q.front(); q.pop();
              ans.push_back(x);
               if(head[x]==-1)continue;
              for(int i=head[x];i!=-1;i=edge[i].next){
                  int v=edge[i].to;
                    q.push(v);
              }

        }
        cnt++;
    }
    cnt--;
    cout<<cnt<<"\n";
    sort(ans.begin(),ans.end());
    int l=ans.size();
    for(int i=0;i<l;i++){
        if(i!=0)cout<<" ";
        cout<<ans[i];
    }
    return 0;
}

L2-027 名人堂与代金劵

思路: 模拟,排序

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;
struct node{
    string name;
    int len;
}a[maxn];
int N,G,K;
int sum=0;
bool cmp(node a,node b){
        if(a.len==b.len){ sum++; return a.name<b.name; }
        return a.len>b.len;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>N>>G>>K;
    int ans=0;
    for(int i=0;i<N;i++){
        cin>>a[i].name;
        cin>>a[i].len;
        if(a[i].len>=G) ans+=50;
        else if(a[i].len>=60) ans+=20;
    }
    sort(a,a+N,cmp);
    cout<<ans<<"\n";
    int cnt=1;
    int pre=-1;
    for(int i=0;cnt<=K;i++){

     if(a[i].len==pre){
         cout<<cnt<<" "<<a[i].name<<" "<<a[i].len<<"\n";
      }
     else{
        pre=a[i].len;cnt=i+1;
        if(cnt>K) break;
        cout<<cnt<<" "<<a[i].name<<" "<<a[i].len<<"\n";
        }
    }
    return 0;
}

L2-028 秀恩爱分得快

思路: 一开始没有考虑编号为0的情况,直接用整型的正负代表男女,后来改成字符输入,然而还是有个测试点不过,
整吐了,爷不写了。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

vector<int> g[maxn];
double a[maxn],b[maxn];
vector<int> ansA,ansB;


int main()
{
    ios::sync_with_stdio(false);
    int f0=1;
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int k; cin>>k;
        while(k--){
            string s;cin>>s;
            int x=stoi(s);
            if(s[0]=='-'&&x==0)f0=0;
            g[i].push_back(x);

        }
    }
    int A,B; cin>>A>>B;
    if(A<0){
        for(int i=0;i<m;i++){
            int flag=0;
            for(int j:g[i]){ if(j==A) flag=1;}
            if(!flag)continue;
            int len=g[i].size();
            for(int j:g[i]){
                if(j>0) a[j]+=1.00/len;
                else if(j==0&&f0){ a[j]+=1.00/len;}
            }
        }
        for(int i=0;i<m;i++){
            int flag=0;
            for(int j:g[i]){ if(j==B) flag=1;}
            if(!flag)continue;
            int len=g[i].size();
            for(int j:g[i]){
                if(j<0) b[-j]+=1.00/len;
                else if (j==0&&!f0){b[j]+=1.00/len;}
            }
        }
        double maxA=-1, maxB=-1;
        for(int i=0;i<n;i++){
         if(a[i]>maxA) maxA=a[i];
         if(b[i]>maxB) maxB=b[i];
        }
        for(int i=0;i<n;i++){
            if(a[i]==maxA)
                ansA.push_back(i);
            if(b[i]==maxB)
                ansB.push_back(i);
        }

        for(int i:ansA){
            if(i==B){
                for(int j:ansB){
                    if(j==-A){
                    if(A==0&&!f0) cout<<"-"<<A<<" "<<B<<"\n";
                    else if(B==0&&!f0)cout<<A<<" -"<<B<<"\n";
                    else
                    cout<<A<<" "<<B<<"\n";
                       return 0;                    }
                }
            }

        }
            for(int i:ansA) {

                cout<<A<<" "<<i<<"\n";
            }
            for(int j:ansB){
                if(j==0&&!f0) cout<<B<<" -"<<-j<<"\n";
                    else
                    cout<<B<<" "<<-j<<"\n";
            }
    }
    else{
    //A>=0 B<0
    for(int i=0;i<m;i++){
            int flag=0;
            for(int j:g[i]){ if(j==A) flag=1;}
            if(!flag)continue;
            int len=g[i].size();
            for(int j:g[i]){
                if(j<0) a[-j]+=1.00/len;
                else if(j==0&&!f0) {a[-j]+=1.00/len;}
            }
        }
        for(int i=0;i<m;i++){
            int flag=0;
            for(int j:g[i]){ if(j==B) flag=1;}
            if(!flag)continue;
            int len=g[i].size();
            for(int j:g[i]){
                if(j>0) b[j]+=1.00/len;
                else if(j==0&&f0){b[j]+=1.00/len;}
            }
        }
        double maxA=-1, maxB=-1;
        for(int i=0;i<n;i++){
         if(a[i]>maxA) maxA=a[i];
         if(b[i]>maxB) maxB=b[i];
        }
        for(int i=0;i<n;i++){
            if(a[i]==maxA)
                ansA.push_back(i);
            if(b[i]==maxB)
                ansB.push_back(i);
        }

        for(int i:ansA){
            if(i==-B){
                for(int j:ansB){
                    if(j==A){
                    if(A==0&&!f0) cout<<"-"<<A<<" "<<B<<"\n";
                    else if(B==0&&!f0)cout<<A<<" -"<<B<<"\n";
                    else
                        cout<<A<<" "<<B<<"\n";

                       return 0;                    }
                }
            }

        }
            for(int i:ansA) {
                    if(i==0&&!f0) cout<<A<<" -"<<-i<<"\n";
                    else
                    cout<<A<<" "<<-i<<"\n";}
            for(int j:ansB) cout<<B<<" "<<j<<"\n";
    }
    return 0;
}

L2-029 特立独行的幸福

思路:方法有点暴力,对于每一个数都判断能否变为1并将途中的数标记,若能变为1则has将原数标为1.若新变成的数已访问过,则退出循环。

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e4+5;

int A,B;
int vis[maxn],has[maxn];
int p[maxn];


int getint(int x){
    int sum=0;
    while(x>0){
        int t=x%10;
        x/=10;
        sum+=t*t;
    }
    return sum;
}
bool is_prime(int x)
{
	if(x<=1)   return false;
    for(int i=2;i*i<=x;i++)
        if(x%i==0)
            return false;
    return true;
}
void judge(int x){

    memset(vis,0,sizeof(vis));
    int c=x;
    int sum=x;
    vis[x]=1;
    while(sum!=1){
        sum=getint(x);
        p[c]++;
        if(sum==1){ has[c]=1;break;}
        if(vis[sum]==1){
            has[c]=-1;break;
        }
        vis[sum]=1;
        has[sum]=-1;
        x=sum;
    }

}
int main()
{
    ios::sync_with_stdio(false);
    cin>>A>>B;
    for(int i=A;i<=B;i++){
     if(!has[i])
        judge(i);
    }
    int flag=0;
    for(int i=A;i<=B;i++){
        if(has[i]==1){
            flag=1;
            if(is_prime(i)) cout<<i<<" "<<2*p[i]<<endl;
            else cout<<i<<" "<<p[i]<<endl;

        }

    }
     if(flag==0)
        cout<<"SAD"<<endl;
    return 0;
}

L2-030 冰岛人

思路: 题目思路不难想,两个for循环遍历五代以内所有的结点,建图和处理字符串有点繁琐,学习了下大佬的写法,定义字符数组
要删去某个位置以后的字符,只需让当前位置的字符等于整数0,还有当输入时每次遇到一个新名字,就给它赋值一个编号。

view code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <unordered_map>
using namespace std;
char fname[21],lname[21],fname1[21],lname1[21];
int n,m,no,flag;
unordered_map<string,int> pos;
bool gender[200001];//1男0女
int f[200001];

bool check(int a,int b) {
   int i=1,j=1;
   for(int A=a; A!=0; A=f[A],i++){
        j=1;
        for(int B=b;B!=0;B=f[B],j++){
            if(i>=5&&j>=5) break;
            if(A==B&&(i<5||j<5))return false;
        }

   }
   return true;
}
int main() {

    scanf("%d",&n);memset(f,0,sizeof(0));
    for(int i = 0;i < n;i ++) {
        scanf("%s%s",fname,lname);
        if(!pos[fname]) pos[fname] = ++ no;
        int len = strlen(lname),d = pos[fname];
        if(lname[len - 1] == 'n') {
            gender[d] = 1;
            lname[len - 4] = 0;
            if(!pos[lname]) {
                pos[lname] = ++ no;
                gender[no] = 1;
            }
            f[d] = pos[lname];
        }
        else if(lname[len - 1] == 'r') {
            gender[d] = 0;
            lname[len - 7] = 0;
            if(!pos[lname]) {
                pos[lname] = ++ no;
                gender[no] = 1;
            }
            f[d] = pos[lname];
        }
        else if(lname[len - 1] == 'm') gender[d] = 1;
        else gender[d] = 0;
    }
    scanf("%d",&m);
    for(int i = 0;i < m;i ++) {
        scanf("%s%s%s%s",fname,lname,fname1,lname);
        int a = pos[fname],b = pos[fname1];
        if(!a || !b) printf("NA\n");
        else if(gender[a] == gender[b]) printf("Whatever\n");
        else printf("%s\n",check(a,b) ? "Yes" : "No");
    }
}

L2-031 深入虎穴

思路:建图,输出离根节点最远的结点

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
struct E{
    int to,next;
}edge[maxn<<1];

int head[maxn],vis[maxn];
int tot=0;

void AddEdge(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;

}

queue<int> q;

int main()
{
    ios::sync_with_stdio(false);
    memset(head,-1,sizeof(head));
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        int k;cin>>k;
        while(k--){
            int v;cin>>v;
            vis[v]=1;
            AddEdge(i,v);
        }
    }
    int root=0;
    for(int i=1;i<=n;i++){
        if(!vis[i]) {root=i;break;}
    }
    q.push(root);
    int ans=n;
    while(q.size()>0){
        int len=q.size();
        while(len--){
            int x=q.front();q.pop();
            for(int i=head[x];i!=-1;i=edge[i].next){
                    int v=edge[i].to;ans=v;
                    if(head[v]==-1) continue;
                    q.push(v);

            }
        }

    }
    cout<<ans;
    return 0;
}

L2-032 彩虹瓶

思路: 栈的经典例题,火车进站

view code
#include <bits/stdc++.h>

using namespace std;
const int maxn=1e5+5;
int a[maxn],s[maxn];

int main()
{
    ios::sync_with_stdio(false);
    int n,m,k;
    cin>>n>>m>>k;
    while(k--)
    {
        for(int i=1; i<=n; i++) cin>>a[i];
        int top=0;
        int now=1;
        int flag=0;
       for(int i=1;i<=n;i++){
            if(a[i]==now){
                now++;
             while(top&&s[top]==now){
                top--;now++;
             }
            }
            else{
                s[++top]=a[i];
                if(top>m){flag=1;} 
            }
       }
    if(!flag&&!top)cout<<"YES\n";
    else cout<<"NO\n";
    }
    return 0;
}
posted @ 2020-11-06 23:41  大塞翁  阅读(313)  评论(0)    收藏  举报