广州大学ACM2021第七周训练 2021.04.13

广州大学ACM第七周训练

链接:GZHUACM第七周
闲话:开始记录的第一场训练赛。这场两点开始,当天补课(高数课旷不得)所以迟到了两个小时,不过前四题很友好,后面的写不了,所以其实也没差。(怎么还押韵了)我要丢掉百度的坏习惯。之前训练没有思路就百度一下题目类型往某个算法或者思维想,并且时不时百度算法模板。在这里提醒下自己,不能白白浪费这么好的机会。
那么就开始吧。

A - 1的个数(简单思维+二进制)

原题链接:计蒜客 - T1179
题意:一个十进制数输出二进制下1的个数。
题解:很简单暴力即可,由于二进制末位与奇偶对应,所以可以不断取奇偶和右移遍历每一个二进制位。

        // violet apricity
// Do all I can do.Do good to be good.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#include<sstream>

#define STD using namespace std;
#define ll long long
#define db double
#define ldb long double
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
#define MAX 88888888
#define INF 0x3f
#define r0 return 0;
#define SYP system("pause");
#define endl '\n'



STD
int main()
{
     
    IOS
    ll a;
    cin>>a;
    ll ans=0;
    while (a)
    {
     
        if(a%2==1)ans++;
        a>>=1;
    }
    cout<<ans<<'\n';
    //SYP
    return 0;
}

B - 实数加法(大浮点数)

原题链接:B - 实数加法
题意:大浮点数相加,形如:ppppppp.qqqqqqq
题解:emmm怎么说呢,大数这玩意说难不难说简单不简单,一个对新手来说考验码力和细节的东西,第一次写是快八个月前了,先后写过好几次,到现在还是不够熟悉。鸿✌说建议学手java或者存个板子,是个好主意。

        // violet apricity
// Do all I can do.Do good to be good.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#include<sstream>

#define STD using namespace std;
#define ll long long
#define db double
#define ldb long double
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
#define MAX 88888888
#define INF 0x3f
#define r0 return 0;
#define SYP system("pause");
#define endl '\n'


int a[1111],b[1111],len;
int main()
{
     
    IOS
    char x;
    std::string s1="",s3="",s2="",s4="";
    //来存下数字,注意整数部分要倒着存,因为是数组存运算时进位要方便
    //相反,因为相加方向不一样,小数不需要倒着存
    while(std::cin>>x&&x!='.')s1=x+s1;//存a整数部分
    std::cin>>s2;//存a小数部分
    while(std::cin>>x&&x!='.')s3=x+s3;//存b整数部分
    std::cin>>s4;//存b小数部分
    if(s1.length()<s3.length())swap(s1,s3);//先处理短的
    for(int i=0;i<s3.length();i++){
     //遍历短的相同部分相加
        a[i]+=s1[i]+s3[i]-2*'0';
        if(a[i]>=10)//进位
        {
     
            a[i+1]+=a[i]/10;
            a[i]%=10;
        }
    }
    for(int i=s3.length();i<s1.length();i++){
     //长的多出来那一部分
        a[i]+=s1[i]-'0';
        if(a[i]>=10)
        {
     
            a[i+1]+=a[i]/10;
            a[i]%=10;
        }
    }
    if(a[s1.length()]) len=s1.length();else len=s1.length()-1;
    //最后是否进位导致边长了一位
    //注意小数和整数相加的差异(方向相反)
    if(s2.length()<s4.length())swap(s2,s4);
    for(int i=0;i<s4.length();i++) b[i]=s2[i]+s4[i]-2*'0';
    for(int i=s4.length();i<s2.length();i++) b[i]=s2[i]-'0';
    for(int i=s2.length()-1;i>=0;i--){
     
        if(i==0&&b[i]>=10)//进位到个位去了
        {
     
            a[0]++;
            b[0]-=10;
        }
        else
        if(b[i]>=10)//还没进位到个位
        {
     
            b[i-1]++;
            b[i]-=10;
        }
    }
    int i=0;
    while(a[i]>=10){
     //小数相加的时候进了位要再处理一次整数进位
        a[i+1]++;
        a[i]-=10;
        i++;
    }
    len=std::max(len,i);//进位后改变长度
    for(int j=len;j>=0;j--)std::cout<<a[j];//输出整数部分
    std::cout<<'.';
    int d=0;
    for(int j=s2.length()-1;j>=0;j--)if(b[j]){
     d=j;break;}//后往前找到非0,即去掉后导0不输出
    for(i=0;i<=d;i++)std::cout<<b[i];//输出小数部分
    std::cout<<'\n';//OVER
    //SYP
    return 0;
}

C - 幂次方(递归+栈模拟)

原题链接:计蒜客 - T2103
题意:用括号的方式把一个非负整数用2的幂次方和表示。
题解:这和寒假在紫书上看的括号序列相比难度低了好多(根本比不了)。可以用栈模拟一下,大概就是:
1.solve(n)对n先取个log(2)得到temp,然后对内部分情况处理:
·若temp>2:说明内部还可以再分,先输出此时的2,再solve(temp)
·若temp==1:说明刚刚好,输出2结束了
·否则输出按正常输出2(temp)
2.然后处理外部:res=n-temp,若res>0说明外部还有,则:
输出+再solve(res)处理外部部分。

        // violet apricity
// Do all I can do.Do good to be good.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#include<sstream>

#define STD using namespace std;
#define ll long long
#define db double
#define ldb long double
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
#define MAX 88888888
#define INF 0x3f
#define r0 return 0;
#define SYP system("pause");
#define endl '\n'




const int mod=10007;
void solve(ll n)
{
     
     int d=2;
     int cnt=0;
     int temp=log(n)/log(2);
     if(temp>2){
     
        std::cout<<"2(";
        solve(temp);
        std::cout<<")";
     }
     else if(temp==1){
     
        std::cout<<"2";
     }
     else {
     
        std::cout<<2<<"("<<temp<<")";
     }
     int res=n-(int)std::pow(2,temp);
     if(res>0){
     
        std::cout<<"+";
        solve(res);
     }
}
int main()
{
     
    IOS
    ll n;
    std::cin>>n;
    solve(n);
    std::cout<<'\n';
    //SYP
    return 0;
}

D - 新运算(模拟)

原题链接:计蒜客 - T1765
题意:定义了三种新运算符。输入一堆数轮流三种运算取模后输出结果。
题解:直接模拟即可。

        // violet apricity
// Do all I can do.Do good to be good.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#include<sstream>

#define STD using namespace std;
#define ll long long
#define db double
#define ldb long double
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
#define MAX 88888888
#define INF 0x3f
#define r0 return 0;
#define SYP system("pause");
#define endl '\n'



STD
const int mod=10007;
int main()
{
     
    IOS
    ll n;
    cin>>n;
    ll cnt=0;
    ll ans=0;
    cin>>ans;
    n--;
    while(n--){
     
        ll x;cin>>x;
        if(cnt==0)ans=((ans*ans%mod)+(x*x%mod))%mod;
        else if(cnt==1)ans=((ans*ans%mod*ans%mod)%mod+x)%mod;
        else if(cnt==2)ans=(ans+(x*x%mod*x%mod)%mod)%mod;
        cnt++;
        cnt%=3;
    }
    cout<<ans<<'\n';
    //SYP
    return 0;
}

到此为止前四到简单题,下面的都是有点难度的,我只会写E,还是莫名其妙过的。

E - Subsequence

原题链接:计蒜客 - 38232
题意:给出一个母串和n个子串,判断子串是否位母串的子串。
题解:可以暴力过,也可以两个数组存个位置。
师兄题解是这么说的:序列自动机,就是找每个点右边的每个字符的位置。
我还不清楚自动机,记得好像写过类似的瞎搞就过了。
我的代码:

        // violet apricity
// Do all I can do.Do good to be good.

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<math.h>
#include<map>
#include<sstream>

#define STD using namespace std;
#define ll long long
#define db double
#define ldb long double
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
#define MAX 88888888
#define INF 0x3f
#define r0 return 0;
#define SYP system("pause");
#define endl '\n'



const int N=111111;
int a[100];
int b[100];
std::vector<int>ans;
const int mod=10007;
char s[N],c[N];
int has[N][130];
void pre(int x,int y)
{
     
    for(int i=0; i<130; i++)has[x][i]=has[x+1][i];
    has[x][y]=x;
}
int main()
{
     
    IOS
    std::cin>>s;
    int n;
    std::cin>>n;
    int len=strlen(s);
    memset(has,-1,sizeof(has));
    for(int i=len-1; i>=0; i--)
    {
     
        int x=(int)s[i];
        pre(i,x);
    }
    while(n--)
    {
     
        std::cin>>c;
        int temp=strlen(c);
        int i=0,j=0;
        for(j=0; j<temp; j++)
        {
     
            int x=(int)c[j];
            int y=has[i][x];
            if(y<i)break;
            i=y+1;
        }
        if(j>=temp)std::cout<<"YES\n";
        else std::cout<<"NO\n";
    }
    //SYP
    return 0;
}

师兄的代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
char s[100010],t[1010];
int nxt[100010][26];
int main(){
     
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>s+1;
    int n=strlen(s+1);
    //建序列自动机
    for(int i=0;i<26;i++) nxt[n][i]=n+1;
    for(int i=n-1;i>=0;i--){
     
        for(int j=0;j<26;j++)
         nxt[i][j]=(s[i+1]=='a'+j?i+1:nxt[i+1][j]);
    }
    int m;
    cin>>m;
    while(m--){
     
      cin>>t+1;
      int len=strlen(t+1);
      int i=0,j=0;
      while(i<len+1){
     
        j=nxt[j][t[i]-'a'];
        if(j==n+1) break;
        i++;
      }
      if(i==len+1) cout<<"YES"<<'\n';
      else cout<<"NO"<<'\n';
    }
}

下面的暂时不会啦,留着以后补吧。
>_<
じゃ、またね

你可能感兴趣的:(广州大学ACM训练记录)