四川大学第二届SCUACM新生赛(同步赛)

文章目录

  • A - 丁姐姐喜欢Fibonacci(规律)
  • B - 丁姐姐喜欢LCS(字符串)
  • C - 俏兔子大战傻贼鹰-Easy Version(模拟)
  • E - [模板]欧拉筛(欧拉筛 + 取模)
  • F - [模板]后缀自动机(思维)
  • G - 走迷宫(递归)
  • I - 排序(模拟)
  • J - n=a * b * c(数学)
  • K - 梅森素数(送分题)
  • L - 双流机场(思维)
  • M - lglg说要有题,于是便有了题。(打表 + 规律)


A - 丁姐姐喜欢Fibonacci(规律)

原题链接:https://ac.nowcoder.com/acm/contest/1838/A


思路: 看着像是一道斐波那契数列题,其实是一道规律题,可以发现,该序列以 “奇奇偶” 的规律一直循环着。


Code(C++):

#include 
using namespace std;
int main(){
    long long n;
    while(cin>>n){
        if(n%3==0)
            cout<<"\"odd\""<<endl;
        else
            cout<<"\"even\""<<endl;
    }
    return 0;
}


B - 丁姐姐喜欢LCS(字符串)

原题链接:https://ac.nowcoder.com/acm/contest/1838/B


思路: 一开始的思路是从 a 串的后面寻找 b 串第一个字符,一找到就标记位置,然后从该位置向右边找,一旦又不相同的就标记并退出循环。样例能过,但就是不知道哪里漏了,不能全部通过。

但有种暴力的方法,就是调用字符串的 substr() 函数,直接在 a 串中枚举所有的字符串,然后与 b 串中从第一个字符开始的相同长度的子串比较,能找到就输出。


Code(C++):

#include 
using namespace std;
int main(){
    string a,b;
    while(cin>>a>>b){
        int vis=0;
        for(int i=0;i<a.size();i++){
            int len = a.size()-i;
            string s=a.substr(i,len);
            if(s==b.substr(0,len)){
                cout<<s<<endl;
                vis=1;
                break;
            }
        }
        if(!vis)
            cout<<"\"NULL!\""<<endl;
    }
    return 0;
}


C - 俏兔子大战傻贼鹰-Easy Version(模拟)

原题链接:https://ac.nowcoder.com/acm/contest/1838/C


题意: 给一个花色和14张牌,以下两种情况可以胡牌:

  1. 四副刻子,每副含三张牌,数字和花色相同,以及一对将,即两张数字和花色相同的牌
  2. 七对子,即每队含两张花色和数字相同的牌

除此之外,每种情况的牌里还不能含有已给出的花色牌,否则不能胡牌。

思路: 用三个数组 s[i], t[i], w[i] 来存相对应花色相对应数字的数量,同时用一个vis 来标记牌中是否已出现已给出的花色,最后判断 vis 以及是否含有胡牌的情况。


Code(C++):

#include 
#include 
using namespace std;
int t[20],s[20],w[20];
int main(){
    int n;  
    while(cin>>n){
        char ch;    cin>>ch;
        while(n--){
            memset(t,0,sizeof(t));
            memset(s,0,sizeof(s));
            memset(w,0,sizeof(w));
            string str;    cin>>str;
            int vis=1;    //标记牌中是否出现已给出的花色
            for(int i=0;i<str.length();i++){
                if(str[i]==ch)    vis=0;
                if(str[i]=='W')
                    w[str[i-1]-'0']++;
                if(str[i]=='T')
                    t[str[i-1]-'0']++;
                if(str[i]=='S')
                    s[str[i-1]-'0']++;
            }
            //flag1记录是否对对胡,flag2记录是否七对子
            int flag1=0,flag2=0;
            for(int i=1;i<=9;i++){
                if(s[i]==3)    flag1++;
                if(w[i]==3)    flag1++;
                if(t[i]==3)    flag1++;
                if(s[i]==2)    flag1++,flag2++;
                if(w[i]==2)    flag1++,flag2++;
                if(t[i]==2)    flag1++,flag2++;
            }
            if((flag1==5 || flag2==7)&& vis)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl; 
        }
    }
    return 0;
}


E - [模板]欧拉筛(欧拉筛 + 取模)

原题链接:https://ac.nowcoder.com/acm/contest/1838/E


题意: 求小于等于 n 的所有质数的阶乘之和。

思路: 这道题有点坑,写着欧拉筛模板题,但其实难点在于取模。某个数字的阶乘 一定是这个数字以及之前数字的倍数。从1 * 2 * 3 * … * a * … * n要模 P,如果a>=p时,a后面再乘一个数%p,数值肯定不变,一定是0,因为这个数是p的整数倍。所以我们要把范围缩小到 min(n, p) 。


Code(C++):

#include 
#include 
#include 
using namespace std;
const int N=1e6+10;
typedef long long ll;
int prime[N],vis[N],x=0;
void isprime()  //欧拉筛
{
    for(int i=2;i<=N;i++){
        if(!vis[i]) prime[x++]=i;
        for(int j=0;j<x;j++){
            if(i*prime[j]>N) break;
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main(){
    isprime();
    int t;    cin>>t;
    while(t--){
        int n,p;
        cin>>n>>p;
        ll ans=0,sum=1;
        for(int i=2;i<=min(n,p);i++){    //求阶乘的代码,很美的代码
            sum=(sum*i)%p;
            if(!vis[i])    
                ans=(ans+sum)%p;
        }
        cout<<ans<<endl;
    }
    return 0;
}


F - [模板]后缀自动机(思维)

原题链接:https://ac.nowcoder.com/acm/contest/1838/F


题意: 又是一道骗子题,真的后缀自动机我还真不会。询问第一个字符串中是否存在一个后缀 P,使得第二个字符串的任何一个前缀的字典序都大于P。

思路: 第二个字符串前缀字典序要尽量小,那么就是只要看首字符就行了,然后只要跟第一个字符串后缀的首字符比较即可,也就是从后往前遍历第一个字符串。

有点坑的就是这个输出是“YE5”和“N0”!!!


Code(C++):

#include 
using namespace std;
int main(){
    int t;    cin>>t;
    while(t--){
        string s1,s2;
        cin>>s1>>s2;
        int vis=0;
        for(int i=s1.size()-1;i>=0;i--){
            if(s2[0]>s1[i]){
                vis=1;
                break;
            }
        }
        if(vis)    cout<<"YE5"<<endl;
        else    cout<<"N0"<<endl;
    }
    return 0;
}


G - 走迷宫(递归)

原题链接:https://ac.nowcoder.com/acm/contest/1838/G


思路: 个人感觉这个题目有点难,先把绕迷宫一圈的情况写出来,然后不断递归。


Code(C++):

#include 
using namespace std;
int n,m,q;
void Out(int x, int n, int m, int k){
    if(n==0 || m==0){
        printf("(%d,%d)\n",x,x-1);
        return;
    }
    if(n==1){    //只有一行的情况
        if(k<m)    printf("(%d,%d)\n",x,x+k);
        else    printf("(%d,%d)\n",x,x+m-1);
        return;
    }
    if(m==1){    //只有一列的情况
        if(k<n)    printf("(%d,%d)\n",x+k,m);
        else    printf("(%d,%d)\n",x+n-1,m);
        return;
    }
    if(k<m){    //k小于m的情况
        printf("(%d,%d)\n",x,x+k);
        return;
    }
    k-=m;    
    if(k<n-1){
        printf("(%d,%d)\n",x+k+1,x+m-1);
        return;
    }
    k-=(n-1);
    if(k<m-1){
        printf("(%d,%d)\n",x+n-1,x+m-2-k);;
        return;
    }
    k-=(m-1);
    if(k<n-2){
        printf("(%d,%d)\n",x+n-2-k,x);
        return;
    }
    k-=(n-2);
    Out(x+1,n-2,m-2,k);
}

int main(){
    int t;  scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&q);
        while(q--){
            int k;  scanf("%d",&k);
            Out(1,n,m,k);
        }
    }
    return 0;
}


I - 排序(模拟)

原题链接:https://ac.nowcoder.com/acm/contest/1838/I


思路: 一道挺复杂的模拟题。看了大佬的代码,思路清晰。


Code(C++):

#include 
#include 
#include 
#include 
using namespace std;
struct node{
    string name;    //队伍名
    int ac;    //ac题目数量
    int sum;    //总共用时
    int fa[15];    //每题罚时
    int cnt[15];    //每题提交次数
    int vis[15];    //每题是否ac状态以及在该题所用时间
}a[55];
bool cmp(node x,node y){
    if(x.ac!=y.ac)    return x.ac>y.ac;
    else{
        if(x.sum!=y.sum)    return x.sum<y.sum;
        else return x.name<y.name;
    }
}
int main(){
    int t;    cin>>t;
    while(t--){
        for(int i=0;i<=50;i++){
            a[i].ac = a[i].sum = 0;
            memset(a[i].fa,0,sizeof(a[i].fa));
            memset(a[i].cnt,0,sizeof(a[i].cnt));
            memset(a[i].vis,0,sizeof(a[i].vis));
        }
        int n,m;    cin>>n>>m;
        map<string,int> mp;
        for(int i=1;i<=m;i++){
            cin>>a[i].name;
            mp[a[i].name]=i;
        }
        int q;    cin>>q;
        while(q--){
            int time; char numb;
            string id,ans;
            cin>>id>>time>>numb>>ans;
            if(a[mp[id]].vis[numb-'A'])    continue;
            else if(ans=="Accepted"){
                a[mp[id]].vis[numb-'A']=time;
                a[mp[id]].cnt[numb-'A']++;
                a[mp[id]].ac++;
                a[mp[id]].sum+=(a[mp[id]].fa[numb-'A']+time);
            }
            else if(ans=="Compilation-Error")    continue;
            else{
                a[mp[id]].cnt[numb-'A']++;
                a[mp[id]].fa[numb-'A']+=20;
            }
        }
        sort(a+1,a+1+m,cmp);
        int rank=1;
        for(int i=1;i<=m;i++){
            if(i!=1 && a[i].ac==a[i-1].ac && a[i].sum==a[i-1].sum)
                cout<<rank;
            else{
                rank=i;
                cout<<rank;
            }
            cout<<' '<<a[i].name<<' '<<a[i].ac<<' '<<a[i].sum<<' ';
            for(int j=0;j<n;j++){
                if(a[i].vis[j])
                    cout<<'+'<<a[i].cnt[j]<<'('<<a[i].vis[j]<<')'<<' ';
                else
                    cout<<'-'<<a[i].cnt[j]<<' ';
            }
            cout<<endl;
        }
        if(t)    cout<<endl;
    }
    return 0;
}


J - n=a * b * c(数学)

原题链接:https://ac.nowcoder.com/acm/contest/1838/J


思路: 直接暴力两层遍历查找,并不断判断更新 c-a 的值。


Code(C++):

#include 
using namespace std;
int main(){
    int t;    cin>>t;
    while(t--){
        int n;    cin>>n;
        int a=0,b=0,c=1e7;
        for(int i=2;i*i*i<=n;i++){
            if(n%i==0){
                for(int j=i;j*j<=n/i;j++){
                    if(n/i%j==0){
                        if(c-a>n/i/j-i)
                            a=i,b=j,c=n/i/j;
                    }
                }
            }
        }
        if(c==1e7)    cout<<"No solution"<<endl;
        else    cout<<n<<'='<<a<<'*'<<b<<'*'<<c<<endl;
    }
    return 0;
}


K - 梅森素数(送分题)

原题链接:https://ac.nowcoder.com/acm/contest/1838/K


思路: 先写个程序暴力把所有符合情况的梅森素数输出,然后挑前五个直接输出即可。


Code(C++):

#include 
using namespace std;
int main(){
    cout<<3<<" "<<7<<" "<<31<<" "<<127<<" "<<8191;
    return 0;
}


L - 双流机场(思维)

原题链接:https://ac.nowcoder.com/acm/contest/1838/L


思路: 题目不难,就是题意的理解有点难度。只要四个角存在不能走的,也就是两个箭头都指向某个角,就输出 “Sad” ,否则输出 “Happy”。


Code(C++):

#include 
using namespace std;
int main(){
    int t;    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        string a,b;
        cin>>a>>b;
        int vis=1;
        if(a[0]=='0'&&b[m-1]=='0')
            vis=0;
        if(a[0]=='1'&&b[0]=='0')
            vis=0;
        if(a[n-1]=='1'&&b[0]=='1')
            vis=0;
        if(a[n-1]=='0'&&b[m-1]=='1')
            vis=0;
        if(vis)    cout<<"Happy"<<endl;
        else    cout<<"Sad"<<endl;
    }
    return 0;
}


M - lglg说要有题,于是便有了题。(打表 + 规律)

原题链接:https://ac.nowcoder.com/acm/contest/1838/M


题意: 求所有小于等于 n 的素数的倒数之和。

思路: 这道题数太大了,直接模拟肯定暴力,那么可以先打表找规律,即分界点,直接输出,时间复杂度就变成了O(1) 。


Code(C++):

/*
#include 
using namespace std;
const int N=1e6+10;
int prime[N],vis[N],x=0;
void isprime(){    //欧拉筛
    for(int i=2;i<=N;i++){
        if(!vis[i]) prime[x++]=i;
        for(int j=0;jN) break;
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main(){
    int t;    cin>>t;
    isprime();
    while(t--){
        int n;    cin>>n;
        double ans=0.0;
        for(int i=2;i<=n;i++){
            if(!vis[i]){
                ans+=1.0/i;
                printf("%d %.0lf\n",i,ans);
            }
        }
        
    }
    return 0;
}
*/
#include 
using namespace std;
int main(){
    int t;    cin>>t;
    while(t--){
        int n;    cin>>n;
        if(n<3)    cout<<0<<endl;
        else if(n<29)    cout<<1<<endl;
        else if(n<11789)    cout<<2<<endl;
        else    cout<<3<<endl;
    }
    return 0;
}


你可能感兴趣的:(算法)