2020上海高校程序设计竞赛暨第18届上海大学程序设计联赛夏季赛(同步赛)

A.同源 暴力枚举加剪枝
思路:因为三个数的最大公因数是k,所以从k的2倍数开始枚举,2k,3k,5*k这样,三个数都提出个k来以后肯定得互质,因此可以用筛法打个素数表,从素数开始枚举a和b,c用n-a-b,然后判断a,b,c三者的gcd是否为1,对于一些比较明显的情况先把它们列出来判断,以进行优化,比如,把k提出来即令n/k,可使得n变小,减小范围

#include
#include
#include

typedef long long ll;

const int N=1e4+10;
ll primes[N],cnt;
bool vis[N];

ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}

void get_primes(ll n)
{
    for(int i=2;i<=n;i++){
        if(!vis[i])primes[cnt++]=i;
        for(int j=0;i*primes[j]<=n/i;j++){
            vis[i*primes[j]]=true;
            if(i%primes[j]==0)break;
        }
    }
}

int main()
{
    int t;
    scanf("%d",&t);
    get_primes(1e4);
    while(t--){
        ll n,k;
        scanf("%lld%lld",&n,&k);
        ll a,b,c;
        if(n%k!=0||n<=k){printf("-1 -1 -1\n");continue;}
        n/=k;
        bool flag=false;
        for(int i=0;i<cnt;i++){
            if(primes[i]>n)break;
            for(int j=i+1;j<cnt;j++){
                if(primes[j]>n)break;
                a=primes[i],b=primes[j];
                c=n-a-b;
                if(c<2)break;
                if(gcd(a,b)!=1||gcd(a,c)!=1||gcd(b,c)!=1)continue;
                else{
                    printf("%lld %lld %lld\n",a*k,b*k,c*k);
                    flag=true;
                    break;
                }
            }
            if(flag)break;
        }
        if(!flag)printf("-1 -1 -1\n");
    }
    return 0;
}

ps:我开始用的1e6我还嫌开小了,没想到居然还是大了,不会算范围有点恐怖。。。

B.分子 模拟题
思路:模拟手动计算分子式过程,有点难度

#include
#include
#include

using namespace std;

typedef long long ll;
string s;
ll i;

ll solve()
{
    ll sum=0,j=0;
    for(;i<s.length();i++){
        ll x=0;
        while(s[i]>='0'&&s[i]<='9'){
            x=x*10ll+(s[i]-'0');//小技巧,10后面加ll将10转化成ll类型
            i++;
        }
        sum+=max(x,1ll)*j;//比较x和1,右边没有x的情况下,x为0时直接取j,此时max是1,否则乘上个x作为数量
        j=0;
        if(s[i]=='C')j=13;
        if(s[i]=='H')j=1;
        if(s[i]=='O')j=17;
        if(s[i]=='('){i++;j=solve();}//遇到右括号递归算出此时括号里的分子量,然后加上去
        else if(s[i]==')')break;//不能直接if判断,用else if作为左括号截止,一遇到左括号就截至的话会漏掉很多计算
    }
    sum+=j;
    return sum;
}

int main()
{
    cin>>s;
    ll sum=solve();
    cout<<sum<<endl;
    return 0;
}

C.爵士 签到题
注意点:字符串读入空格用getline(cin,s),不需要高精度除法,double强制类型转换即可
ps:教训就是没看清题意直接做,题意是一句话只要有一个2就是二次元,cnt++,而不是cnt计算所有2,所以一个字符串遇到一个2以后就break,无需继续计算

#include
#include
#include
#include

using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--){
        int n,cnt=0;
        cin>>n;
        string s;
        getline(cin,s);
        for(int i=0;i<n;i++){
            getline(cin,s);
            int len=s.length();
            for(int j=0;j<len;j++){
                if(s[j]=='2'){cnt++;break;}
            }
        }
        /*int key=0;高精度除法
        printf("%d.",cnt/n);
        if(cnt%n==0)printf("0000000000");
        while(cnt%n&&key<10){
            cnt*=10;
            key++;
            printf("%d",cnt/n);
            cnt%=n;
        }*/
        printf("%.10lf\n",(double)cnt/n);
        //printf("\n");
    }
    return 0;
}

你可能感兴趣的:(2020上海高校程序设计竞赛暨第18届上海大学程序设计联赛夏季赛(同步赛))