码迷,mamicode.com
首页 > 其他好文 > 详细

Gym 100338H High Speed Trains(高精度)

时间:2015-08-29 09:52:49      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:高精度

Gym 100338H High Speed Trains

题意:

求n个城市相互连通的方案数。

思路:

HDU 4390迷之相似。
一共有n个城市,那么就有n(n?1)/2条边,每条边均有两种可能,选或不选。那么我们用ans[n]来表示n个城市相互连通的方案数:

ans[n]=2n(n?1)/2?C1n?ans[n?1]?C2n?ans[n?2]?...?Cn?2n?ans[2]?C0n?ans[0]

答案 = 所有 - 一个城市独立的情况 - 两个城市独立的情况 - … - n-2个城市独立的情况 - 0个城市独立的情况(不可能有一个城市独立啦

但是这题数据不要求模除。。
打表的长度大概是50KB,超过了提交代码最大30KB的限制;

所以要动用高精度,用C++的高精度很浪费,因为ans数组与组合数都需要高精度才能存下,但前者最多几十位,后者n=100的时候大概上千位,而一般高精度的模板是不支持动态修改数组长度的。。所以很容易MLE,虽然通过修改重载函数可以办到,但是还是麻烦啊!

高精度Java写起来可以简化不少,但这题又有个巨坑。。就是要用文件重定向输入输出,臣妾做不到啊。。虽然后来发现就是几行代码的事

当然啦,直接用python的话,好像可以秒杀吧?

代码:

C++,Java,python都写了一份,看个人喜好吧。

C++:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
using namespace std;
typedef long long lint;
typedef long long ll;
typedef long long LL;
const int maxn = 2000;
const int maxm = 50;

struct bign1
{
    int len, s[maxm];

    bign1()//构造函数
    {
        memset(s, 0, sizeof(s));
        len = 1;
    }
    bign1 operator = (const char * num)
    {
        len = strlen(num);
        for (int i = 0; i < len; i++)
            s[i] = num[len - i - 1] - ‘0‘;
        return *this;
    }

    bign1(const char * num){ *this = num; }//支持初始化操作

    bign1 operator = (int num)
    {
        char s[maxm];
        sprintf(s, "%d", num);//把num输出到字符串s中
        *this = s;
        return *this;
    }

    bign1(int num){ *this = num; }

    string str() const     //利用string类把字符串数组转换为字符串,方便用<<,>>输出
    {
        string res = "";
        for (int i = 0; i < len; i++)
            res = (char)(s[i] + ‘0‘) + res;
        if (res == "")  res = "0";
        return res;
    }

    bign1 operator + (const bign1& b) const//定义加法
    {
        bign1 c;
        c.len = 0;
        for (int i = 0, g = 0; g || i < max(len, b.len); i++)//要两个数的位数都计算一便
        {
            int x = g;//g为其余数
            if (i < len)    x += s[i];
            if (i < b.len)  x += b.s[i];
            c.s[c.len++] = x % 10;
            g = x / 10;
        }
        return c;
    }

    bign1 operator += (const bign1& b)
    {
        *this = *this + b;
        return *this;
    }

    void clean()//把0排除,得到真实的len
    {
        while (len > 1 && !s[len - 1])
            len--;
    }

    bign1 operator - (const bign1& b) const
    {
        bign1 c;
        c.len = 0;
        for (int i = 0, g = 0; i < len; i++)
        {
            int x = s[i] - g;//减去借1
            if (i < b.len)  x -= b.s[i];//上减下
            if (x >= 0)     g = 0;
            else
            {
                g = 1;//x<0说明需要向前借1
                x += 10;//将x变为正
            }
            c.s[c.len++] = x;
        }
        c.clean();//x可能为0
        return c;
    }

    bign1 operator -= (const bign1& b)
    {
        *this = *this - b;
        return *this;
    }


    bign1 operator * (const bign1& b) const
    {
        bign1 c;
        c.len = len + b.len;//结果的位数最大为两个因子位数之和
        for (int i = 0; i < len; i++)
        for (int j = 0; j < b.len; j++)
            c.s[i + j] += s[i] * b.s[j];//对应位置的积的和,累加起来就是结果
        for (int i = 0; i < c.len - 1; i++)
        {
            c.s[i + 1] += c.s[i] / 10;//进位的值
            c.s[i] %= 10;//余数位
        }
        c.clean();
        return c;
    }

    bign1 operator *= (const bign1& b)
    {
        *this = *this * b;
        return *this;
    }
};
struct bign
{
    int len, s[maxn];

    bign()//构造函数
    {
        memset(s, 0, sizeof(s));
        len = 1;
    }
    bign(bign1& A) {
        len = A.len;
        for(int i = 0; i < len; i++) {
            s[i] = A.s[i];
        }
    }
    bign operator = (const char * num)
    {
        len = strlen(num);
        for (int i = 0; i < len; i++)
            s[i] = num[len - i - 1] - ‘0‘;
        return *this;
    }

    bign(const char * num){ *this = num; }//支持初始化操作

    bign operator = (int num)
    {
        char s[maxn];
        sprintf(s, "%d", num);//把num输出到字符串s中
        *this = s;
        return *this;
    }

    bign(int num){ *this = num; }

    string str() const     //利用string类把字符串数组转换为字符串,方便用<<,>>输出
    {
        string res = "";
        for (int i = 0; i < len; i++)
            res = (char)(s[i] + ‘0‘) + res;
        if (res == "")  res = "0";
        return res;
    }

    bign operator + (const bign& b) const//定义加法
    {
        bign c;
        c.len = 0;
        for (int i = 0, g = 0; g || i < max(len, b.len); i++)//要两个数的位数都计算一便
        {
            int x = g;//g为其余数
            if (i < len)    x += s[i];
            if (i < b.len)  x += b.s[i];
            c.s[c.len++] = x % 10;
            g = x / 10;
        }
        return c;
    }

    bign operator += (const bign& b)
    {
        *this = *this + b;
        return *this;
    }

    void clean()//把0排除,得到真实的len
    {
        while (len > 1 && !s[len - 1])
            len--;
    }

    bign operator - (const bign& b) const
    {
        bign c;
        c.len = 0;
        for (int i = 0, g = 0; i < len; i++)
        {
            int x = s[i] - g;//减去借1
            if (i < b.len)  x -= b.s[i];//上减下
            if (x >= 0)     g = 0;
            else
            {
                g = 1;//x<0说明需要向前借1
                x += 10;//将x变为正
            }
            c.s[c.len++] = x;
        }
        c.clean();//x可能为0
        return c;
    }

    bign operator -= (const bign& b)
    {
        *this = *this - b;
        return *this;
    }


    bign operator * (const bign& b) const
    {
        bign c;
        c.len = len + b.len;//结果的位数最大为两个因子位数之和
        for (int i = 0; i < len; i++)
        for (int j = 0; j < b.len; j++)
            c.s[i + j] += s[i] * b.s[j];//对应位置的积的和,累加起来就是结果
        for (int i = 0; i < c.len - 1; i++)
        {
            c.s[i + 1] += c.s[i] / 10;//进位的值
            c.s[i] %= 10;//余数位
        }
        c.clean();
        return c;
    }

    bign operator *= (const bign& b)
    {
        *this = *this * b;
        return *this;
    }
};

istream& operator >> (istream &in, bign& x)//
{
    string s;
    in >> s;
    x = s.c_str();
    return in;
}
ostream& operator << (ostream &out, const bign& x)
{
    out << x.str();
    return out;
}

bign1 c[110][110];
void init2() {
    c[0][0] = 1;
    for(int i = 1; i <= 100; i++) {
        c[i][0] = 1;
        for(int j = 1; j <= i; j++) {
            c[i][j] = c[i-1][j-1]+c[i-1][j];
        }
    }
}
int n;
bign ans[110];
void init() {
    ans[0] = 1; ans[1] = 0; ans[2] = 1;
    bign t = 1;
    int last = 0;
    for(int i = 3; i <= n; i++) {
        bign tmp = 0;
        for(int j = 1; j <= i; j++) {
            tmp += ((bign)c[i][j])*ans[i-j];
        }
        for(int j = last; j < i*(i-1)/2; j++) t = t * 2;
        //if(i==100) cout << t << endl;
        last = i*(i-1)/2;
        ans[i] = t - tmp;

    }
    cout << ans[n] << endl;
}
int main(){
    freopen("trains.in", "r", stdin);
    freopen("trains.out", "w", stdout);

    init2();
    cin >> n;
    init();
    return 0;
}



Java:

import java.math.BigInteger;
import java.util.Scanner;
import java.io.*;

public class Main {

    public static void main(String[] args) throws FileNotFoundException {
        FileInputStream cin = new FileInputStream("trains.in");
        FileOutputStream cout = new FileOutputStream("trains.out");
        Scanner in = new Scanner(cin);
        PrintStream out = new PrintStream(cout);

        BigInteger[][] C = new BigInteger[110][110];
        C[0][0] = BigInteger.ONE;
        for (int i = 1; i <= 100; i++) {
            C[i][0] = C[i][i] = BigInteger.ONE;
            for (int j = 1; j < i; j++) {
                C[i][j] = C[i - 1][j].add(C[i - 1][j - 1]);
            }
        }

        int n = in.nextInt();
        in.close( ) ;
        BigInteger[] ans = new BigInteger[110];
        for (int i = 0; i < ans.length; i++) {
            ans[i] = BigInteger.valueOf(1);
        }
        BigInteger two = BigInteger.valueOf(2);
        for (int i = 3; i <= n; i++) {
            for (int j = 2; j < i; j++) {
                if (j == i - 1)
                    ans[i] = ans[i].add(ans[j].multiply(two.pow(j).subtract(
                            BigInteger.ONE)));
                else
                    ans[i] = ans[i].add(ans[j].multiply(two.pow(j).multiply(
                            C[i - 1][j])));
            }
        }
        out.println(ans[n]);
        out.close() ;
    }
}

python:

import sys
C = []
def init():
    for i in range(115):
        C.append([])
        for j in range(115):
            C[i].append(0)
    C[0][0] = 1
    for i in range( 1 , 110 ):
        C[i][0] = 1
        for j in range( 1 , i+1 ):
            C[i][j] = C[i-1][j-1] + C[i-1][j]
    #print( C[4][2] )

def work( n ):
    ans = []
    ans.append( 1 )
    ans.append( 0 )
    ans.append( 1 )
    t = 1
    last = 0
    for i in range( 3 , 105 ):
        tmp = 0
        for j in range( 1 , i+1 ):
            tmp = tmp + C[i][j] * ans[i-j]
        for j in range( last , int( i * ( i - 1 ) / 2 ) ):
            t = t * 2
        last = i * ( i - 1 ) // 2
        ans.append( t - tmp )
    print( ans[n] )

sys.stdin = open(‘trains.in‘, ‘r‘)
sys.stdout = open(‘trains.out‘, ‘w‘)   
init()
n = input()
work( int( n ) )

版权声明:博主表示授权一切转载啦,不过要写上原作者哦:)

Gym 100338H High Speed Trains(高精度)

标签:高精度

原文地址:http://blog.csdn.net/qq_15714857/article/details/48065709

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!