Gym 102800

原题链接

A题:

没啥好讲的 挺清晰的一道题

#include<iostream>
#include<cstring>
int main()
{
    using namespace std;
    char a[13][4]={"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};//这里用二维数组存
    int T;
    cin>>T;
    while(T--)
    {
        char b[4][3];
        cin>>b[0]>>b[1]>>b[2];
        bool flag=false;
        for(int i=0;i<12;++i)
        {
            if(strcmp(a[i],b[0])==0&&strcmp(a[(i+4)%12],b[1])==0&&strcmp(a[(i+7)%12],b[2])==0)
            {
                flag=true;
                cout<<"Major triad"<<endl;
                break;
            }
            else if(strcmp(a[i],b[0])==0&&strcmp(a[(i+3)%12],b[1])==0&&strcmp(a[(i+7)%12],b[2])==0)
            {
                flag=true;
                cout<<"Minor triad"<<endl;
                break;
            }
        }
        if(!flag)
            cout<<"Dissonance"<<endl;
    }
}

B题:

        这题也是非常水的一道题目了 很快就去写了发现运行不了 以为是scanf不能这么用 反斜杠输不了之类的 所以马上就换方法写了 后面补题的时候发现可以这样的 就是换行符也会被读进去 与'h'不匹配 程序就运行不下去了

        血亏 这么水的题 早该a了的

        所以下次再遇到类似的要格式化输入字符串的情况 记得getchar()的使用

#include<iostream>
#include<cstdio>
#include<algorithm>
int main()
{
    using namespace std;
    int T;
    cin>>T;
    while(T--)
    {
        int n,k;
        char a[50];
        int b[1005];
        cin>>n>>k;
        for(int i=0;i<n;++i)
        {
            getchar();//★注意这里一定要加getchar()
            scanf("http://acm.hit.edu.cn/problemset/%d",&b[i]);
        }

        sort(b,b+n);
        for(int i=0;i<k-1;i++)
            cout<<b[i]<<' ';
        cout<<b[k-1]<<endl;
    }
}

C题:

        其实这题训练赛的时候想到大概思路了  但是没能往动态规划上面想 导致实现不了代码

        下面是我现在自己的理解....可能会有些不对

        这题好像就是..设一个二维数组dp[ i ][ j ] 表示主串前 j 位中能和子串前 i 位匹配的个数  然后下面子串外层循环 主串内层循环

        如果没有匹配到相同字符:那么主串中前 j 位中能和子串前 i 位匹配的个数 就等于主串中前 j-1 位中能和子串前 i 位匹配的个数

        在讲匹配到相同字符的情况前 先举个例子想一下 比如主串是eeettt 子串是et 当子串第一位(i=1)循环结束时,dp[1][3]是不是等于3(匹配到三个相等字符),当循环子串第二位 主串循环到第四位时 主串中前 j 位中能和子串前 i 位匹配的个数 即eeet中能和et匹配的个数 是不是等于eee中能和e匹配的个数 即=dp[ i-1 ][ j-1 ]=3 

        现在开始讨论 当匹配到相同字符时:如果子串循环到第一位 dp[ i ][ j ]就等于dp [ i ][ j-1 ]+1(主串前面能和子串第一位匹配的个数+1)

        如果子串循环到后面 dp[ i ][ j ]=dp[ i-1 ][ j-1 ]+dp [ i ][ j-1 ](主串中前 j-1 位中能和子串前 i 位匹配的个数+主串中前j-1位能和子串前i-1位匹配的个数 

#include<iostream>
#include<cstdio>
#include<cstring>
__int64 dp[1005][5005];//表示主串前j位中能和子串前i位匹配的个数
//dp太大了 必须要放在全局里
int main()
{
    using namespace std;
    const int mod=1e9+7;
    char s[5005];
    char t[1005];
    scanf("%s%s",s+1,t+1);
    //我觉得这里的+1好巧妙 之前一直不知道该怎么跳过第一位不存
    int len1=strlen(t+1);
    int len2=strlen(s+1);
    memset(dp,0,sizeof(dp));//其实这里不用memset也可以 大概因为dp是全局数组吧
    for(int i=1;i<=len1;++i)//子串
    {
        for(int j=1;j<=len2;++j)//主串
        {
            if(s[j]==t[i])//如果匹配到相等字符
            {
                if(i==1)
                    dp[i][j]=(1+dp[i][j-1])%mod;
                else
                    dp[i][j]=(dp[i-1][j-1]+dp[i][j-1])%mod;//
            }
            else
                dp[i][j]=dp[i][j-1];
        }
    }
    cout<<dp[len1][len2]<<endl;
}

E题:

        思维题 不过既然是思维题 自己写肯定是写不出了 但是这题我都能理解到 说明不是很难 可以好好看一看得

        同样注意数据量过大不能用cin cout L题是队友写的 当时印象还没那么深刻 赛后补题的时候写这题一直TLE 很烦 后来跟那个L题队友抱怨的时候突然就一拍脑门 哦不能用cin啊!这回我一定再也忘不掉了

        这题大概思路就是 找到一个最小值minn

        如果只有一个最小值 那么这个值取余任何数都为这个最小值 即minn可以和与他相邻的所有数都进行操作变为minn(minn%x=minn) 最后就会只剩下minn 长度为1 所以其实计算出最小值个数cnt=1时可以直接输出长度为1 但是我的代码没有这么写

        如果不止一个最小值 就要分情况讨论了

        如果数组里的所有的数除了它本身 都是最小值minn的倍数:可以自己举几个例子试一下 因为最小值和其他的抵消之后 两个最小值相操作只能变成0 就不能继续操作了 所以最小值两两抵消 如果cnt是偶数 剩下的长度会是(cnt/2) 如果是奇数就需要再多加一个1了 其实就是向上取整的意思

        如果有某个数x不是minn的倍数:minn可以和周围和他成倍数关系的全部抵消变成minn 当遇到某个数x不是minn的倍数 可以进行(x%minn)的操作  得到的数一定比minn还要小 我们又可以用这个比minn更小的值对其他所有数进行操作(这个值在数组里的个数一定只有一个)就会把其他所有的数都抵消掉 最后会只剩下这个数 因此长度为1

#include<iostream>
#include<cstdio>
__int64 a[1000010];//记得放全局
int main()
{
    using namespace std;
    int T;
    cin>>T;
    while(T--)
    {
        int minn=1e9+10;//初始化最小值
        int n;
        int cnt=0;//记录最小值的个数
        cin>>n;//输入数组个数
        for(int i=0;i<n;++i)
        {
            scanf("%d",&a[i]);
            if(a[i]<minn)//如果找到更小的值
            {
                minn=a[i];//更新最小值
                cnt=1;//重新计数
            }
            else if(a[i]==minn)//如果又有一个最小值
                cnt++;//个数加一
        }
        bool flag=false;
        for(int i=0;i<n;++i)
        {
            if(a[i]%minn!=0)//如果找到一个数不是最小值的倍数 可以直接跳出循环了 因为长度必然为1
            {
                flag=true;
                break;
            }
        }
        if(flag)
            printf("1\n");
        else
            printf("%d\n",(cnt+1)/2);//向上取整 也可以用ceil函数
    }
}

L题:

        这题其实是挺水的一道题了 但是一直超时 反复看了很久 哪一个循环都是必不可少的 还很疑惑为什么别人一遍就能过了 最后突然醒悟是cin cout的问题 数据量过大一定要用printf scanf啊救命 这题错了得有七次吧 数不清的罚时了 谨记

#include<cstdio>
using namespace std;
long long aa[1000005];
int main()
{
    long long a,c;
    long long m;
    scanf("%lld%lld%lld",&a,&m,&c);
    long long t,i,t1,t2;
    for(i=1;i<=a;i++)
        scanf("%lld",&aa[i]);
    while(c--)
    {
        scanf("%lld%lld",&t,&i);
        t=aa[i]*t;
        t1=t%m;
        t2=t/m;
        if(t2%2==0)
            printf("%lld\n",t1);
        else
            printf("%lld\n",m-t1);
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值