Gym 101466 部分题解

题目链接

纪念一下和库里布莱恩特的这场菜鸡互啄。

3星Gym,一共做出来7个题。感觉最大的收获就是意识到了二分的重要性,还有就是学习到了一种新的排序方法——计数排序(好像又叫桶排序)。下面根据题的难度从简到难记录一下。

H题:

按照题意打印即可。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;

int main()
{
    int n;
    cin>>n;
    rep(i,1,n)
    {
        if(i==1)
        {
            cout<<"*";
            rep(j,1,n-2)
                cout<<" ";
            cout<<"* ";
            rep(j,1,n)
                cout<<"*";
            cout<<endl;
            continue;
        }
        if(i==n)
        {
            rep(j,1,n)
                cout<<"*";
            cout<<" *";
            rep(j,1,n-2)
                cout<<" ";
            cout<<"*";
            continue;
        }
        cout<<"*";
        rep(j,1,n-2)
            cout<<" ";
        cout<<"*";
        cout<<" *";
        rep(j,1,n-2)
            cout<<" ";
        cout<<"*"<<endl;
    }
    return 0;
}

D题:

说是有两种机器A和B,对于A:输入x,返回2*x+1;对于B,输入x,返回2*x+2。开始有0个,要得到n个,问应该怎样使用机器。

只需要判断n的奇偶性就性了,如果n为奇数,用A,否则用B,一直判断,直到n为0,然后倒序输出即可。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
char ans[1000010];
int main()
{
    ll n;
    cin>>n;
    mem(ans,0);
    int k=0;
    while(n)
    {
        if(n%2==0)
        {
            ans[k]='B';
            k++;
            n=(n-2)/2;
        }
        else
        {
            ans[k]='A';
            k++;
            n=(n-1)/2;
        }
    }
    repp(i,k-1,0)
    cout<<ans[i];
    return 0;
}

 B题:

有一棵树,给你n个数,a[i]表示某一层的每个节点都可以有a[i]个子节点,问这颗树最多有多少个节点。猜都能猜出来,让深度越浅的层数有越多的节点。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
int a[40];
bool cmp(int a1,int a2)
{
    return a1>a2;
}
int main()
{
    int n;
    cin>>n;
    rep(i,0,n-1)
    cin>>a[i];
    sort(a,a+n,cmp);
    ll ans=1;
    ll cnt=1;
    rep(i,0,n-1)
    {
        ans+=(cnt*a[i]);
        cnt=cnt*a[i];
    }
    cout<<ans;
    return 0;
}

 C题:

在三维平面里,给你n个点的坐标,第一个点表示地球,其余n-1个点表示其他行星,问从其他n-1个行星到地球连线,共能产生多少条不同的直线。只需要算出向量坐标然后比较即可。比如两个向量,判断其是否共线,假设这两个个向量分别为(x1,y1,z2),(x2,y2,z2),如果满足x1/x2==y1/y2&&x1/x2==z1/z2,则共线,否则不共线。但是,需要注意的是,坐标可能有0,0不能做除数,所以要转化成乘法来做,及判断x1*y2==y2*x2&&x1*z2==z1*x2&&y2*z1==z2*y1是否成立。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
struct node{
    int x1,y1,z1;
    int x2,y2,z2;
}a[5010];
int vis[5010];
int main()
{
    int n;
    cin>>n;
    int x,y,z;
    cin>>x>>y>>z;
    rep(i,0,n-2)
    {
        cin>>a[i].x1>>a[i].y1>>a[i].z1;
        a[i].x2=x-a[i].x1;
        a[i].y2=y-a[i].y1;
        a[i].z2=z-a[i].z1;
    }
    mem(vis,0);
    int cnt=0;
    rep(i,0,n-2)
    {
        if(vis[i])
            continue;
        vis[i]=1;
        cnt++;
        rep(j,0,n-2)
            if(a[i].x2*a[j].y2==a[i].y2*a[j].x2&&a[i].x2*a[j].z2==a[i].z2*a[j].x2&&a[i].z2*a[j].y2==a[i].y2*a[j].z2)
                vis[j]=1;
    }
    cout<<cnt;
    return 0;
}

F题:

猜的题意,因为我看好几个人都一发过了,然后我感觉题应该很简单,然后就猜了一下,码了一下,交了一发,过了......

判断n个“三角形”是不是都能构成三角形,如果存在不能构成三角形的三角形,输出NO,否则输出YES。

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
struct node{
    int x,y,z;
}a[100010];
int main()
{
    int n;
    cin>>n;
    int xx,yy,zz;
    int f=0;
    rep(i,0,n-1)
    {
        scanf("%d%d%d",&xx,&yy,&zz);
        a[i].x=max(max(xx,yy),zz);
        a[i].z=min(min(xx,yy),zz);
        a[i].y=xx+yy+zz-a[i].x-a[i].z;
    }
    rep(i,0,n-1)
    {
        if(a[i].z+a[i].y>a[i].x)
            continue;
        else
            {f++;break;}
    }
    if(f)
        cout<<"NO";
    else
        cout<<"YES";
    return 0;
}

 

E题:

给你两个字符串A和B,再给你一个整数n,让你输出B在A中出现次数大于等于n次的最长前缀串,如果不存在输出impossible。

首先需要知道,如果B的长度为i的前缀串在A中出现的次数不足n次,那么B中长度为i+1的前缀串在A中出现的次数一定也不足n次。并且我们可以在O(n+m)时间范围内判断一个长度为m的模式串在一个长度为n的主串中出现的次数(直接套模板)。如果我们对模式串的长度从1到strlen(B)枚举的话,时间复杂度为1e5*1e5,会超时,所以我们可以用二分,二分模式串的长度。

二分真的很重要啊,当算法超时的时候一定要想想二分啊!

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
char S[100010];
char TT[100010];
char T[100010];
int slen,tlen,ttlen;
char ans[100010];
int nxt[100010];
void getNext()
{
    int i,j;
    i=0;j=-1;nxt[0]=-1;
    while(i<tlen)
    {
        if(j==-1||T[i]==T[j])
            nxt[++i]=++j;
        else
            j=nxt[j];
    }
}
int KMP_Count()
{
    int ret=0;
    int i,j=0;
    if(slen==1&&tlen==1)
    {
        if(S[0]==T[0])
            return 1;
        else
            return 0;
    }
    getNext();
    for(i=0;i<slen;i++)
    {
        while(j>0&&S[i]!=T[j])
            j=nxt[j];
        if(S[i]==T[j])
            j++;
        if(j==tlen)
        {
            ret++;
            //j=i+1;  //如果求主串中包含几个模式串 j=i+1
            j=nxt[j];//如果求模式串在主串中出现的次数 j=nxt[j]
        }
    }
    return ret;
}
int main()
{
    gets(S);
    gets(TT);
    int k;
    cin>>k;
    ttlen=strlen(TT);
    slen=strlen(S);
    int f=0;
    ans[0]='!';
    int l=1,r=ttlen;
    while(l<=r)
    {
        int mid=(l+r)/2;
        rep(j,0,mid-1)
            T[j]=TT[j];
        T[mid]='\0';
        tlen=mid;
        if(KMP_Count()<k)   //KMP_Count()返回模式串T在主串S中出现的次数
            r=mid-1;
        else
            {strcpy(ans,T);l=mid+1;}
    }
    if(ans[0]=='!')
        cout<<"IMPOSSIBLE";
    else
        cout<<ans;
    return 0;
}

 J题:

某人想写出n个数,但是当他写完m(m<n)个数时,他不想写了,要直接构造出来n-m个数,构造公式:a[i]=(a[i-m]+a[i-m+1])%3e7。然后进行k次询问,每次询问给出一个数b[i],问将上面n个数排好序后,第b[i]个数是多少。

这个题有两种方法可以做,一种是计数排序(桶排序),另一种是思维......实际上和计数排序差不多。

1、计数排序

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
int a[30000010];
int b[30000010];
int c[10000010];
int main()
{
    int n,m,q;
    cin>>n>>m>>q;
    int maxx=-10;
    mem(b,0);
    rep(i,1,m)
    {
        scanf("%d",&a[i]);
        maxx=max(maxx,a[i]);
        b[a[i]]++;
    }
    rep(i,m+1,n)
    {
        a[i]=(a[i-m]+a[i-m+1])%30000000;
        maxx=max(maxx,a[i]);
        b[a[i]]++;  //b[i]表示i出现的次数
    }
    int k=1;
    //计数排序
    rep(i,0,maxx)
    {
        rep(j,1,b[i])
            {c[k]=i;k++;}   //数组c即为将a数组排好序的结果
    }
    int x;
    while(q--)
    {
        scanf("%d",&x);
        cout<<c[x]<<endl;
    }
    return 0;
}

2、思维,实际上都差不多。 

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<cstdlib>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define repp(i,n,a) for(int i=n;i>=a;i--)
#define ll long long
#define ull unsigned long long
#define mem(a,x) memset((a),(x),sizeof ((a)))//x只能是0或-1或false或true
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"************"<<endl
#define lowbit(x) ((x)&(-x))
#define lson rt<<1
#define rson rt<<1|1
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/(__gcd(a,b))
#define inf 0x3f3f3f3f//1e9+6e7
#define eps 1e-8
#define mod 1e9+7
#define N 100010
const double pi=acos(-1.0);
using namespace std;
int a[30000010];
int b[30000010];
int main()
{
    int n,m,q;
    cin>>n>>m>>q;
    mem(b,0);
    rep(i,1,m)
        {scanf("%d",&a[i]);b[a[i]]++;}
    rep(i,m+1,n)
    {
        a[i]=(a[i-m]+a[i-m+1])%30000000;
        b[a[i]]++;
    }
    rep(i,1,30000000)
        b[i]=b[i]+b[i-1];
    int x;
    while(q--)
    {
        scanf("%d",&x);
        int l=0,r=30000000;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(b[mid]>=x&&b[mid-1]<x)
                {cout<<mid<<endl;break;}
            if(b[mid]<x)
                l=mid+1;
            else
                r=mid-1;
        }
    }
    return 0;
}

其他的暂时不会了,慢慢补吧......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值