2020牛客暑期多校训练营(第三场)题解

A - Clam and Fish(贪心)

思路:

贪心,首先有鱼一定钓鱼,将没有鱼的天数单独拉出来考虑

首先从无鱼的第一天开始枚举,若当前天数有蛤蜊就收集,若啥都没,则用手头的蛤蜊换鱼

同时注意当当前手头的蛤蜊数等于剩余的天数,则剩余天数每天都可以换一条鱼

代码:

#include<iostream>
#include<algorithm>
 using namespace std;
 const int maxn=2e6+10;
 char s[maxn];
 int main()
 {
     int t,n;
     scanf("%d",&t);
     while(t--){
         scanf("%d%s",&n,s);;
         int ans=0,num=0,x=0;
         for(int i=0;i<n;i++)
             if(s[i]=='0'||s[i]=='1') num++;
         for(int i=0;i<n;i++){
             num-=(s[i]=='0'||s[i]=='1');
             if(s[i]=='0'){
                 if(x){
                     ans++;
                     x--;
                 }
             }
            else if(s[i]=='1'){
                if(x+1>num&&x){
                    x--;
                    ans++;
                }    
                else x++;
            } 
             else ans++;
         }
         cout<<ans<<endl;
     }
    return 0;
 }

B - Classical String Problem(模拟)

思路:

其实操作一只是在改变字符串循环的开头而已,我们只要记录头指针即可

代码:

#include"bits/stdc++.h"
using namespace std;
char s[2000005];
int n;
int q;
int p;
int main()
{
    int T;
    char ss[4];
    scanf("%s",s);
    n=strlen(s);
    cin>>T;
    while(T--)
    {
        scanf("%s",ss);scanf("%d",&p);
        if(ss[0]=='M')
        {
            q+=p;
            q%=n;
            if(q<0)q+=n;
        }
        else
        {
            int t;
            printf("%c\n",s[(p+q-1)%n]);
        }
    }
    return 0;
}

C - Operation Love(几何)

思路:

我们找三条比较有特征的边,大拇指外侧,底侧,小指外侧长度分别为$6,9,8$

用叉积判断点是顺时针还是逆时针给出的,然后看顺时针/逆时针方向上这三条边顺序,即可判断左右手

代码:

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=30;
double a[maxn],b[maxn];
double d[maxn];
double jud(int s,int t){
    return sqrt((a[s]-a[t])*(a[s]-a[t])+(b[s]-b[t])*(b[s]-b[t]));
}
 
int S(int p1,int p2,int p3){  // 1 right  2 left
    double ans=(a[p1]-a[p3])*(b[p2]-b[p3])-(b[p1]-b[p3])*(a[p2]-a[p3]);
    if(ans>0) return 1;
    else return 0;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        for(int i=1;i<=20;i++){
            scanf("%lf%lf",&a[i],&b[i]);   
        }
        int p1,p2,p3;
        int get8=0,get9=0;
        for(int i=1;i<=19;i++){
            d[i]=jud(i,i+1);
        }d[20]=jud(20,1);
        d[21]=d[1]; a[21]=a[1]; b[21]=b[1];a[22]=a[2]; b[22]=b[2];
        for(int i=1;i<=20;i++){
            if(abs(d[i]-9)<=0.01 &&  abs(d[i+1]-8)<=0.01){
                p1=i;p2=i+1;p3=i+2;
                if(S(p1,p2,p3)) cout<<"right"<<endl;
                else cout<<"left"<<endl;
            }
            if(abs(d[i]-8)<=0.01 &&  abs(d[i+1]-9)<=0.01){
                p3=i;p2=i+1;p1=i+2;
                if(S(p1,p2,p3)) cout<<"right"<<endl;
                else cout<<"left"<<endl;
            }
        }
         
    }
}

D - Points Construction Problem(构造)

代码:

#include"bits/stdc++.h"
using namespace std;
int a[60];
int b[60];
int dx,dy;
int px[60],py[60];
int m[7][7]={1, 2,  9,  10,  25,  26,  49,
             4, 3,  8,  11,  24,  27,  48,
             5, 6,  7,  12,  23,  28,  47,
             16, 15,  14,  13,  22,  29,  46,
             17, 18,  19,  20,  21,  30,  45,
             36, 35,  34,  33,  32,  31,  44,
             37, 38,  39,  40,  41,  42,  43
};
void out(int t)
{
    for(int i=1;i<=t;i++)printf("%d %d\n",px[i]+dx,py[i]+dy);
    dx+=50;
}
void out2(int t,int m)
{
    if(m==b[t])
    {
        out(t);
        return;
    }
    if(t>=4&&m-2==b[t-1])
    {
        out(t-1);
        printf("%d %d\n",-1+dx-50,0+dy);
        return;
    }
    for(int i=1;i<=t;i++)
    {
        if(b[t-i]<=m-b[i]&&m-b[i]<=a[t-i])
        {
            out(i);
            out2(t-i,m-b[i]);
            return;
        }
    }
}
int main()
{
    a[1]=b[1]=4;
    for(int i=2;i<55;i++)
    {
        a[i]=a[i-1]+4;
    }
    int k=0,t=0;
    for(int i=2;i<55;i++)
    {
        if(t<k/2)b[i]=b[i-1],t++;
        else
        {
            b[i]=b[i-1]+2;
            k=k+1;
            t=0;
        }//cout<<i<<":"<<b[i]<<endl;//<<"   "<<k<<endl;
    }
    //for(int i=0;i<55;i++)cout<<i<<":"<<b[i]<<endl;
    for(int i=0;i<7;i++)for(int j=0;j<7;j++)
    {
        px[m[i][j]]=i;
        py[m[i][j]]=j;
    }//for(int i=1;i<50;i++)cout<<px[i]<<" "<<py[i]<<endl;
    //for(int i=1;i<51;i++)cout<<i<<":"<<b[i]<<"-"<<a[i]<<endl;
    px[50]=7;py[50]=3;
    //
    //
    //
    //
    //
    //out2(11,16);
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        if(m%2)printf("No\n");
        else if(b[n]<=m&&m<=a[n])
        {
            printf("Yes\n");
            out2(n,m);
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

E - Two Matchings(DP)

 代码:

#include"bits/stdc++.h"
#define ll long long
using namespace std;
int a[200015];
ll dp[200035];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",a+i);
        sort(a,a+n);
        for(int i=7;i<n;i+=2)
        {
            dp[i-4]=max(dp[i-4],dp[i-6]);
            dp[i]=dp[i-4]+a[i-3]-a[i-4];
        }
        ll ans=0;
        for(int i=1;i<n;i+=2)ans=max(ans,dp[i]);
        ans=(ll)2*(a[n-1]-a[0])-2*ans;
        ;
        printf("%lld\n",ans);
        for(int i=0;i<n+10;i++)dp[i]=0;
    }
    return 0;
}

F - Fraction Construction Problem(拓展欧几里得)

代码:

#include"bits/stdc++.h"
#define ll long long
using namespace std;
void gcd(int a,int b,int *x,int *y)
{
    if(b==0)
    {
        *x=1;
        *y=0;
        return;
    }
    //x*a-y*b=1
    int k=a/b;
    int c=a%b;
    //a=k*b+c
    int x0,y0;
    gcd(b,c,&x0,&y0);
    //x=-y0,y=-y0k-x0
    ll xx=-y0,yy=-y0*(ll)k-x0;
    //xx+b;yy+a
    ll kk=y0/b;
    xx=xx+kk*b;
    yy=yy+kk*a;
    if(xx<0)xx=xx+b,yy=yy+a;
    *x=(int)xx;
    *y=(int)yy;
}
int isprime(int a)
{
    int p=min((int)sqrt((double)a)+2,a-1);
    for(int i=2;i<=p;i++)
    {
        if(a%i==0)return i;
    }
    return 0;
}
int main()
{//cout<<37*37-3*444;
    int T;
    cin>>T;
    while(T--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int p=isprime(b);
        if(p==0)
        {
            if(b==1)printf("-1 -1 -1 -1\n");
            else
            {
                if(a%b==0)
                {
                    printf("%d %d %d %d\n",a/b+1,1,1,1);
                }
                else printf("-1 -1 -1 -1\n");
            }
        }
        else
        {
            if(a%p==0)
            {
                printf("%d %d %d %d\n",a/p+1,b/p,1,b/p);
            }
            //
            else
            {
                int q=b/p;
                while(1)
                {
                    if(q%p==0)q/=p;
                    else break;
                }
                p=b/q;
                if(q==1)
                {
                    printf("-1 -1 -1 -1\n");
                    continue;
                }
                int x,y;
                gcd(q,p,&x,&y);
                printf("%lld %d %lld %d\n",x*(ll)a,p,y*(ll)a,q);
            }
        }
    }
    return 0;
}

G - Operating on a Graph(并查集+启发式合并)

思路:

我们用并查集去维护每个点到底属于哪个集合

但是本题比较棘手的地方在于合并,但是我们可以发现这样的一个规律,对于每个点至多只会进行一次把相邻的点变为与自己同集合的操作

所有,我们对于每个集合开一个链表用于维护本集合中的边缘点(未进行过操作的点)

在进行吞并操作的时候,一个集合的边缘点就变成了与其相邻集合的所有边缘点,所以这里会有一个合并所有集合边缘点的操作

这个合并操作我们使用启发式合并,每次都将小的集合加入大的集合中,能有有效的降低时间复杂度

代码:

#include<iostream>
#include<algorithm>
#include<vector>
 using namespace std;
 const int maxn=8e5+10;
 vector<int> a[maxn];
 int fa[maxn];
 int find(int x)
 {
     return fa[x]==x?x:fa[x]=find(fa[x]);
 }
 int main()
 {
     int t,n,m,q,x,u,v;
     scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
            fa[i]=i;
            a[i].clear();
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            a[u].push_back(v);
            a[v].push_back(u);
        }
        scanf("%d",&q);
        while(q--){
            scanf("%d",&x);
            if(x!=fa[x]) continue;
            vector<int> tmp;
            for(int i=0;i<a[x].size();i++){
                int v=a[x][i];
                int rt=find(v);
                if(x!=rt){
                    if(tmp.size()<a[rt].size()) swap(a[rt],tmp);
                    for(int j=0;j<a[rt].size();j++)
                        tmp.push_back(a[rt][j]);
                    a[rt].clear();
                    fa[rt]=x;
                }
            }
            swap(tmp,a[x]);
        }
        for(int i=0;i<n;i++)
            printf("%d ",find(i));
        printf("\n");
    } 
    return 0;
 }

L - Problem L is the Only Lovely Problem(模拟)

思路:

直接进行比对即可

代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
 using namespace std;
 typedef long long ll;
 int main()
 {
    string s;
    cin>>s;
    int flag=0;
    string tmp="lovely";
    for(int i=0;i<tmp.size();i++){
        if(tmp[i]==s[i]||(s[i]-'A'+'a')==tmp[i]){
            continue;
         }
        flag=1;
        break;
     }
         
    if(flag) cout<<"ugly";
    else cout<<"lovely";
    return 0;
 }

 

posted @ 2020-07-20 00:54  overrate_wsj  阅读(250)  评论(0编辑  收藏  举报