2016CCPC长春 一些题解

B - Fraction
温暖的签到,求一个奇奇怪怪的式子的解。
不能用除法,我们手写几次就会发现上一次的分子分母交换一下就可以,最后记得约分

#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
int a[20],b[20];
int gcd(int a,int b)
{
    return a == 0 ? b: gcd(b%a,a);
}
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;
}

一年之前,我还会这种巧妙地办法。
当然还有一种暴力的做法,写一个分数类

#include <iostream>
#include <algorithm>
using namespace std;
struct num
{
    int a,b;
    num(){}
    num(int _a,int _b)
    {
        int gcd = __gcd(_a,_b);
        a = _a/gcd,b = _b/gcd;
    }
    num operator + (const num &y) const
    {
        return num(y.b*a+y.a*b,b*y.b);
    }
    num operator / (const num &y) const
    {
        return num(a*y.b,b*y.a);
    }
    void reduce()
    {
        int gcd = __gcd(a,b);
        a = a/gcd,b = b/gcd;
    }
};
int a[101],b[101];
int main()
{

    int ca,cat = 1;
    cin>>ca;
    while(ca--)
    {
        int n;
        cin>>n;
        for(int i = 1;i<=n;i++)
        {
            cin>>a[i];
        }
        for(int i = 1;i<=n;i++)
        {
            cin>>b[i];
        }
        num ans = num(a[n],1);;
        for(int i = n;i >= 1;i--)
        {
            if(i == 1) ans = num(b[i],1)/ans;
            else ans = num(a[i-1],1)+(num(b[i],1)/ans);
            ans.reduce();
            //cout<<ans.a<<' '<<ans.b<<endl;
        }
        cout<<"Case #"<<cat++<<": "<<ans.a<<' '<<ans.b<<endl;

    }
    return 0;
}

D - Triangle
把一个从1到n的序列拿出最少的一部分数,让剩下的数形不成三角形。
想到 :a+b == c 只要将fib数留下来就行了,这样任意两个数加起来都是<=c 的
F - Harmonic Value Description
构造题,首先第k大的值是n+k-2。我们根据这个构造一下,分成奇偶分开排列就行了
H - Sequence I
看出来是要用kmp了,发现不用动b串,我们枚举每次匹配的开头,然后按照间隔p进行匹配就行了,因为只匹配p次,时间复杂度O(能过)
或者将a数组每次采样,然后kmp,时间是一样的

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define next fuck
using namespace std;
const int MAXN = 1e6 + 10;
int next[MAXN],a[MAXN],b[MAXN];
int p;
void pre(int x[],int m)
{
    memset(next,0,sizeof(next));
    int i,j;
    j = next[0] = -1;
    i = 0;
    while(i <=m)
    {
        while(-1 != j && x[i] != x[j]) 
            j = next[j];
        next[++i] = ++j;
    }
}
int kmp(int x[],int m,int y[],int n)
{
    int i,j;
    int ans = 0;
    pre(x,m);
    for(int ii = 0;ii<p;ii++)
    {
        i = ii;
        j = 0;
        int pos = 0;
        while(i < n)
        {
            while(-1 !=j && y[i] != x[j])
                j = next[j];
            i+=p,j++;
            if(j >= m)
                ans++,j = next[j];
        }
    }
    return ans;
}
int main()
{

    int ca,cat = 1;
    scanf("%d",&ca);
    while(ca--)
    {
        int n,m;
        scanf("%d%d%d",&n,&m,&p);
        for(int i = 0;i<n;i++) scanf("%d",&a[i]);
        for(int i = 0;i<m;i++) scanf("%d",&b[i]);
        int ans = 0;
        if(m > n/p) ans = 0;
        else ans = kmp(b,m,a,n);
        printf("Case #%d: %d\n",cat++,ans);
    }
    return 0;
}

J - Ugly Problem
最近写了不少java,手基本熟了,可以转型java选手了
我们把一个数切成两半,前一半构造一个回文串,然后接着处理剩下的数字,这里要分成奇数偶数判断一下,同时要注意1000这样的特例

import java.lang.*;
import java.math.BigInteger;
import java.util.Scanner;
import java.util.Vector;

public class Main {

    static Vector<String> vec;
    public static void dfs(String s)
    {

        BigInteger rs = new BigInteger(s);

        int len = s.length();
        if(len == 1)
        {
            vec.add(s);
            return ;
        }
        if(rs.subtract(BigInteger.ONE).toString().length() < len)
        {
            vec.add(rs.subtract(BigInteger.ONE).toString());
            vec.add("1");
            return;
        }
        String l = s.substring(0, len/2);
        String r = s.substring(len/2+(len %2),len);
        String res = "";
        if(rev(l).compareTo(r) <= 0)
        {
            res= l;
            if(len % 2 == 1)
            {
                res = res + s.charAt(len/2);
            }
             res = res + rev(l);
        }
        else
        {
            res = l;
            if(len % 2 == 1)
            {
                res = res + s.charAt(len/2);
                res = (new BigInteger(res).subtract(BigInteger.ONE)).toString();
                res =res + rev(res.substring(0,len/2));
            }
            else
            {
                res = (new BigInteger(res).subtract(BigInteger.ONE)).toString();
                res = res + rev(res);
            }
            //else res = res+"99"+ res;
        }
        vec.add(res);
        rs = rs.subtract(new BigInteger(res));
        //System.out.println(rs);
        if(rs.compareTo(BigInteger.ZERO) == 0) return;
        dfs(rs.toString());
        return;
    }
    public static  String rev(String s)
    {
        StringBuilder sb = new StringBuilder(s);
        sb.reverse();
        return sb.toString();
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int ca = sc.nextInt(),cat = 1;
        vec = new Vector<String>();
        while(ca-- != 0)
        {
            String s = sc.next();
            vec.clear();
            dfs(s);

            System.out.printf("Case #%d:\n%d\n",cat++,vec.size());
            for(String vs : vec)
            {
                System.out.println(vs);
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值