Gym 100338H High Speed Trains(高精度)

来源:互联网 发布:ios禁止软件联网 编辑:程序博客网 时间:2024/04/30 06:55

Gym 100338H High Speed Trains

题意:

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

思路:

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

ans[n]=2n(n1)/2C1nans[n1]C2nans[n2]...Cn2nans[2]C0nans[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-6using 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 sysC = []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 ) )
0 0