CCPC 2016 长春 几道水题的题解

长春这场我是一个人做的,于是到3个小时的时候我就放弃了……
这场比赛想法提比较多,我看了下题解,想法题一般暴力是能出结果的,但是需要你去简化问题或者简化方法。哪里有那么多的想法,只有无穷多的简化罢了……
还是看题吧:
B - Fraction
这道题的题意就是照着题中的公式计算,一看数据范围就知道是暴力了,计算的方法稍稍模拟下就出来了,一开始没有想对,直接做了除法,wa了几次才反应过来

#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
int main()
{
    //ios::sync_with_stdio(false);
   // freopen("input.txt","r",stdin);
    //scanf("%d",&T);
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n = 0;
        scanf("%d",&n);
        for(int i = 1;i<=n;i++) scanf("%d",&a[i]);
        for(int j = 1;j<=n;j++) scanf("%d",&b[j]);

        int p = b[n],q = a[n];
        for(int i = n-1;i>0;i--)
        {
            p += a[i] * q;
            q*=b[i];
            swap(q,p);
        }
        int t = gcd(q,p);
        printf("Case #%d: %d %d\n",cat++,p/t,q/t);
    }
    return  0;
}

D - Triangle
这道题应该是最水的一道题了,题意是从一个1…N的全排列中去掉几个数使得剩下的数中任意三个都不能形成三角形。
首先端这可能需要打表,在找了半天规律之后,终于发现是斐波那契数列,只要判断有多少个小于N的斐波那契数,最后减去就行可以了,原因是因为任意三个斐波那契数之间都不能形成三角形,而且没有特例……这道题算是考了一个逆向思维吧

#include <bits/stdc++.h>
#include <cstring>
#define ll long long
using namespace std;
int a[100];
int cnt[100];
int main()
{
    a[1] = 1,a[2] = 2;
    for(int i = 3;i<=22;i++)
    {
        a[i] = a[i-1] +a[i-2];
    }
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        //memset(cnt,0,sizeof(cnt));
        int n = 0;
        int ans = 0;
        scanf("%d",&n);
        for(int i = 1;i<=20;i++)
        {
            if(a[i] <= n) ans++;
        }
        printf("Case #%d: %d\n",cat++,n-ans);
    }
    return  0;
}

F - Harmonic Value Description
这道题的意思是求出一个排列的相邻两个数的最大公约数的和是第K大的那个排列,有点绕,但是不难理解。
这道题的做法是这样的:首先如果两个数是相邻的,那么他们的GCD肯定是1,一个数X和2*X的GCD是K,那么第K大的排列,说明,2*K和K在最前面,那么将剩下的数输出就行

#include <bits/stdc++.h>
#include <cstring>
#define ll long long
using namespace std;
int main()
{
    //ios::sync_with_stdio(0);
    int ca,cat = 1;
    cin>>ca;
    int n,k;
    while(ca--)
    {
        printf("Case #%d: ",cat++);
        cin>>n>>k;
        printf("%d %d",2*k,k);
        for(int i = k-1;i>0;i--)
        {
            printf(" %d",i);
        }
        for(int i = k+1;i<=n;i++)
        {
            if(i != 2*k) printf(" %d",i);
        }
        printf("\n");
    }
    return  0;
}

F - Four Operations
这道题的提议是在一个书中间按顺序填上加减乘除四个符号,形成一个表达式,然后求出其中最大的结果。一开始我想的是DFS加剪枝,后来时间原因没写出来。后来和其他人交流的时候发现这是一道贪心……
做法是这样的,因为将一个数变成a+b-c*d/e然后要求最小值,那么我们肯定要让c*d/e的结果最小,让a+b的结果最大,那么我们先给a和b从前往后最大N-3的空间,剩下的位数两位分别给c,d,剩下的就是e了。这个贪心策略是正确的,但是我们会想直接给c,d,e都是一位数,其实不然,譬如111991

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
char str[100001];
int num[100001];
ll getnum(int s,int t)
{
    ll res = 0;
    for(int i = s;i<=t;i++)
    {
        res*=10;
        res+=num[i];
    }
    return res;
}
int main()
{
    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        scanf("%s",str);
        int n = strlen(str);
        for(int i = 1;i<=n;i++)
        {
            num[i] = str[i-1] - '0';
        }
        ll ans = -INF;
        for(int i = 2;i<=n-3;i++)
        {
            ll c,d,e;
            ll add = max(getnum(1,i-1)+getnum(i,i),getnum(1,1)+getnum(2,i));
            c = num[i+1],d = num[i+2];
            e = getnum(i+3,n);
            ans = max(ans,add - c*d/e);
        }
        printf("Case #%d: %lld\n",cat++,ans);
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值