POJ 2084 Game of Connections

Game of Connections
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 4839 Accepted: 2515

Description

This is a small but ancient game. You are supposed to write down the numbers 1, 2, 3, . . . , 2n - 1, 2n consecutively in clockwise order on the ground to form a circle, and then, to draw some straight line segments to connect them into number pairs. Every number must be connected to exactly one another. 
And, no two segments are allowed to intersect. 
It's still a simple game, isn't it? But after you've written down the 2n numbers, can you tell me in how many different ways can you connect the numbers into pairs? Life is harder, right?

Input

Each line of the input file will be a single positive number n, except the last line, which is a number -1. 
You may assume that 1 <= n <= 100.

Output

For each n, print in a single line the number of ways to connect the 2n numbers into pairs.

Sample Input

2
3
-1

Sample Output

2
5

Source


/*
卡特兰数 + 大数运算,一开始自己推公式得到的结论是:
f(2 * n) = f(0) * f(2 * n - 2) + f(2) * f(2 * n - 4) + f(4) * f(2 * n - 6) + ... + f(2 * n - 2) * f(0);
然后纯粹基于递推来算, 发现结果是对的,但是速度太慢,超时了。后来想了想,这不就是卡特兰数吗?呵呵,问题解决了
F(n) = F(0) * F(n - 1) + F(1) * F(n - 2) + ... + F(n - 1) * F(0) = C(2 * n, n) / (n + 1), F(0) = 1
代码很长,大部分是自己写的大数运算工具模板, 哈哈
*/
#include <iostream>
#include <string>
#define BIGINTEGER_LEN_TYPE int
#define MAX_N 201
using namespace std;

string num[MAX_N];
string cval[MAX_N][MAX_N];

//大数加法
string bigIntegerAdd(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE lenl = static_cast<BIGINTEGER_LEN_TYPE>(left.size());
    BIGINTEGER_LEN_TYPE lenr = static_cast<BIGINTEGER_LEN_TYPE>(right.size());
    std::string res = "";
    
    //get the minimum length of the two string
    BIGINTEGER_LEN_TYPE minLen = (lenl <= lenr) ? lenl : lenr;
    BIGINTEGER_LEN_TYPE maxLen = (lenl <= lenr) ? lenr : lenl;
    std::string longerStr = (lenl <= lenr) ? right : left;
    
    int residue = 0, sum = 0, quotient = 0;
    //add operation, first part
    BIGINTEGER_LEN_TYPE pos1;
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        sum = (left[pos1] - '0') + (right[pos1] - '0') + quotient;
        quotient = sum / 10;
        residue = sum % 10;
        res += residue + '0';
    }
    //add operation, second part
    for(BIGINTEGER_LEN_TYPE pos2 = pos1; pos2 <= maxLen - 1; pos2 ++)
    {
        sum = (longerStr[pos2] - '0') + quotient;
        quotient = sum / 10;
        residue = sum % 10;
        res += residue + '0';
    }
    //add the extra carry
    while(quotient != 0)
    {
        residue = quotient % 10;
        quotient = quotient / 10;
        res += residue + '0';
    }
    //std::cout<<"res size:"<<res.length()<<std::endl;
    return res;
}

//大数乘法
string bigIntegerMult(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE minLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE maxLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    std::string longerStr = "";
    std::string shorterStr = "";
    std::string res = "";
    //get the longer and short strings and corresponded length
    if(left.length() <= right.length())
    {
        minLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
        maxLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
        shorterStr = left;
        longerStr = right;
    }
    else
    {
        minLen = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
        maxLen = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
        shorterStr = right;
        longerStr = left;
    }
    BIGINTEGER_LEN_TYPE pos1 = 0;
    BIGINTEGER_LEN_TYPE pos2 = 0;
    //start from the first digit of the shorter string
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        //multiply each digit of the longer string
        int residue = 0, product = 0, quotient = 0;
        BIGINTEGER_LEN_TYPE curPos = 0;
        for(pos2 = 0; pos2 <= maxLen - 1; pos2++)
        {
            curPos = pos1 + pos2;
            //new space
            if(res.length() == 0 || curPos > int(res.length() - 1))
            {
                product = (shorterStr[pos1] - '0') * (longerStr[pos2] - '0') + quotient;
                quotient = product / 10;
                residue = product % 10;
                res += residue + '0';
            }
            //space already exists, just add the original value to product
            else
            {
                product = (shorterStr[pos1] - '0') * (longerStr[pos2] - '0') + quotient + (res[curPos] - '0');
                quotient = product / 10;
                residue = product % 10;
                res[curPos] = residue + '0'; 
            }
        }
        //process the extra quotient
        //start position
        curPos = maxLen + pos1;
        while(quotient != 0)
        {
            if(res.length() == 0 || curPos > int(res.length() - 1))
            {
                residue = quotient % 10;
                quotient = quotient / 10;
                res += residue + '0';
            }
            else
            {
                quotient = quotient + (res[curPos] - '0');
                residue = quotient % 10;
                quotient = quotient / 10;
                res[curPos] = residue + '0';
            }
            curPos++;
        }
    }
    //std::cout<<res.length()<<std::endl;
    return res;
    
}

//对字符串str进行翻转
string getReverse(const string str)
{
    std::string revStr = "";
    BIGINTEGER_LEN_TYPE pos = static_cast<BIGINTEGER_LEN_TYPE>(str.length()) - 1;
    for(; pos >= 0; pos--)
        revStr += str[pos];
    return revStr;
}

//比较两个大数的大小
int bigIntegerCmp(const string left, const string right)
{
    BIGINTEGER_LEN_TYPE lenl = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE lenr = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    if(lenl < lenr)
        return -1;
    else if(lenl > lenr)
        return 1;
    return strcmp(getReverse(left).c_str(), getReverse(right).c_str());
}

//大数减法
string bigIntegerSub(const string left, const string right)
{
    std::string biggerStr = "";
    std::string smallerStr = "";
    std::string res = "";
    BIGINTEGER_LEN_TYPE minLen = 0;
    BIGINTEGER_LEN_TYPE maxLen = 0;
    
    //get the bigger integer and smaller integer
    int cmpRes = bigIntegerCmp(left, right);
    if(cmpRes == -1 || cmpRes == 0)
    {
        smallerStr = left;
        biggerStr = right;
    }
    else
    {
        smallerStr = right;
        biggerStr = left;
    }
    //get related size
    minLen = static_cast<BIGINTEGER_LEN_TYPE>(smallerStr.length());
    maxLen = static_cast<BIGINTEGER_LEN_TYPE>(biggerStr.length());
    
    int extra = 0, temp = 0, subRes = 0;
    //subtraction operation, first part
    BIGINTEGER_LEN_TYPE pos1;
    for(pos1 = 0; pos1 <= minLen - 1; pos1++)
    {
        int curL = biggerStr[pos1] - '0';
        int curR = smallerStr[pos1] - '0';
        temp = 0;
        while((subRes = (curL - curR + 10 * temp - extra)) < 0)
            temp++;
        res += subRes + '0';
        extra = temp;
    }
    //subtraction operation, second part
    for(BIGINTEGER_LEN_TYPE pos2 = pos1; pos2 <= maxLen - 1; pos2 ++)
    {
        int curL = biggerStr[pos2] - '0';
        temp = 0;
        while((subRes = (curL + 10 * temp - extra)) < 0)
            temp++;
        res += subRes + '0';
        extra = temp;
    }
    //remove the zero at head
    while(res[res.length() - 1] == '0' && res.length() >= 2)
        res = res.substr(0, res.length() - 1);
    
    //std::cout<<"res size:"<<res.length()<<std::endl;
    return res;
}

//把整数转换为字符串
string getStr(int a)
{
    string res = "";
    if(a == 0) return "0";
    else
    {
        while(a)
        {
            res = char(a % 10 + '0') + res;
            a = a / 10;
        }
    }
    return res;
}

//大数除法
void bigIntegerDiv(const std::string left, const std::string right, std::string & quotient, std::string & residual)
{
    int type = bigIntegerCmp(left, right);
    //left < right
    if(type == -1)
    {
        quotient = "0";
        residual = left;
        return;
    }
    //left = right
    else if(type == 0)
    {
        quotient = "1";
        residual = "0";
        return;
    }
    //left > right
    //initialize the related data 
    quotient = "";
    residual = "";
    std::string dividend = left;
    std::string divisor = right; 
    BIGINTEGER_LEN_TYPE lenDend = static_cast<BIGINTEGER_LEN_TYPE>(left.length());
    BIGINTEGER_LEN_TYPE lenDsor = static_cast<BIGINTEGER_LEN_TYPE>(right.length());
    
    std::string temp = "";
    std::string curStr = "";
    std::string tryStr = "";
    BIGINTEGER_LEN_TYPE curPos = 0;
    int choice = 0;
    bool visitedFirst = false;
    //start from the head of the dividend
    for(curPos = lenDend - 1; curPos >= 0; curPos--)
    {
        curStr = dividend[curPos] + curStr;
        //curStr > divisor, can be processed
        if(bigIntegerCmp(curStr, divisor) >= 0)
        {
            //try the quotient from 1 to 10 until the result of choice * divisor is the biggest less than curStr
            for(choice = 1; choice <= 10; choice++)
            {
                temp = "";
                temp += char(choice + '0');
                tryStr = bigIntegerMult(divisor, temp);
                if(bigIntegerCmp(tryStr, curStr) > 0)
                {
                    choice--;
                    break;
                }
            }
            //right now, choice is just the current quotient and should be appended ahead to quotient
            quotient = char(choice + '0') + quotient;
            temp = "";
            temp += char(choice + '0');
            //update curStr
            curStr = bigIntegerSub(curStr, bigIntegerMult(divisor, temp));
            if(curPos == 0)
                residual = curStr;
            //set visitedFirst, visitedFirst is used to prevent producing '0' quotient
            visitedFirst = true;
        }
        //curStr is not enough to be divided by divisor, so the current quotient is '0' and should be appended to 'quotient'
        else if(visitedFirst)
            quotient = '0' + quotient;
        if(curPos == 0)
        {
            residual = curStr;
            break;
        }
        if(curStr == "0")
            curStr = "";
    }
    residual = curStr;
    return;
}

string getCval(int p, int q)
{
    if(p == q || q == 0) return "1";
    if(q == 1) return getReverse(getStr(p));
    
    if(cval[p][q] != "0") return cval[p][q];
    
    return cval[p][q] = bigIntegerAdd(getCval(p - 1, q - 1), getCval(p - 1, q));
} 

//计算k的卡特兰数,下标从0开始
string solve1(int k)
{
    if(num[k] != "0") return num[k];
    string quotient, residual;

    bigIntegerDiv(getCval(2 * k, k), getReverse(getStr(k + 1)), quotient, residual);
    
    return quotient;
}

int main()
{
    int i, j, p;
    for(i = 1; i < MAX_N; i++) 
    {
        num[i] = "0";
        for(j = 1; j < MAX_N; j++)
            cval[i][j] = "0"; 
    }
    num[1] = "1";
    while(scanf("%I64d", &p) && p != -1)
        cout<<getReverse(solve1(p))<<endl;
    return 0;
}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值