uva 10844 - Bloques(数论+高精度)

题目链接:uva 10844 - Bloques

题目大意:给出一个n,表示有1~n这n个数,问有多少种划分子集的方法。

解题思路:递推+高精度。

1

1 2

2 3 5

5 7 10 15

15 20 27 37 52

  • dp[i][j]=dp[i?1][j?1]+dp[i][j?1]
  • dp[i][0]=dp[i?1][i?1]
  • ans[i]=dp[i][i]

需要用到高精度,并且缩进。

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
const int MAXN = 1005;
const int MOD = 1e8;

struct bign {
    int len, num[MAXN];

    bign () {
        len = 0;
        memset(num, 0, sizeof(num));
    }
    bign (int number) {*this = number;}
    bign (const char* number) {*this = number;}

    void DelZero ();
    void Put ();

    void operator = (int number);
    void operator = (char* number);

    bool operator <  (const bign& b) const;
    bool operator >  (const bign& b) const { return b < *this; }
    bool operator <= (const bign& b) const { return !(b < *this); }
    bool operator >= (const bign& b) const { return !(*this < b); }
    bool operator != (const bign& b) const { return b < *this || *this < b;}
    bool operator == (const bign& b) const { return !(b != *this); }

    void operator ++ ();
    void operator -- ();
    bign operator + (const int& b);
    bign operator + (const bign& b);
    bign operator - (const int& b);
    bign operator - (const bign& b);
    bign operator * (const int& b);
    bign operator * (const bign& b);
    bign operator / (const int& b);
    //bign operator / (const bign& b);
    int operator % (const int& b);
};

/*Code*/

const int N = 905;
bign dp[2][N], ans[N];

void init () {
    ans[1] = 1;
    dp[1][1] = 1;
    for (int i = 2; i < N; i++) {
        int u = i%2;
        int v = 1-u;

        dp[u][1] = ans[i-1];;
        for (int j = 2; j <= i; j++)
            dp[u][j] = dp[u][j-1] + dp[v][j-1];

        ans[i] = dp[u][i];
    }
}

int main () {
    int n;
    init ();
    while (scanf("%d", &n) == 1 && n) {
        printf("%d, ", n);
        ans[n].Put();
        printf("\n");
    }
    return 0;
}

void bign::DelZero () {
    while (len && num[len-1] == 0)
        len--;

    if (len == 0) {
        num[len++] = 0;
    }
}

void bign::Put () {

    printf("%d", num[len-1]);
    for (int i = len-2; i >= 0; i--)
        printf("%08d", num[i]);
}

void bign::operator = (char* number) {
    len = strlen (number);
    for (int i = 0; i < len; i++)
        num[i] = number[len-i-1] - ‘0‘;

    DelZero ();
}

void bign::operator = (int number) {

    len = 0;
    while (number) {
        num[len++] = number%MOD;
        number /= MOD;
    }

    DelZero ();
}

bool bign::operator < (const bign& b) const {
    if (len != b.len)
        return len < b.len;
    for (int i = len-1; i >= 0; i--)
        if (num[i] != b.num[i])
            return num[i] < b.num[i];
    return false;
}

void bign::operator ++ () {
    int s = 1;

    for (int i = 0; i < len; i++) {
        s = s + num[i];
        num[i] = s % 10;
        s /= 10;
        if (!s) break;
    }

    while (s) {
        num[len++] = s%10;
        s /= 10;
    }
}

void bign::operator -- () {
    if (num[0] == 0 && len == 1) return;

    int s = -1;
    for (int i = 0; i < len; i++) {
        s = s + num[i];
        num[i] = (s + 10) % 10;
        if (s >= 0) break;
    }
    DelZero ();
}

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

bign bign::operator + (const bign& b) {
    int bignSum = 0;
    bign ans;

    for (int i = 0; i < len || i < b.len; i++) {
        if (i < len) bignSum += num[i];
        if (i < b.len) bignSum += b.num[i];

        ans.num[ans.len++] = bignSum % MOD;
        bignSum /= MOD;
    }

    while (bignSum) {
        ans.num[ans.len++] = bignSum % MOD;
        bignSum /= MOD;
    }

    return ans;
}

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

bign bign::operator - (const bign& b) {
    int bignSub = 0;
    bign ans;
    for (int i = 0; i < len || i < b.len; i++) {
        bignSub += num[i];
        bignSub -= b.num[i];
        ans.num[ans.len++] = (bignSub + 10) % 10;
        if (bignSub < 0) bignSub = -1;
    }
    ans.DelZero ();
    return ans;
}

bign bign::operator * (const int& b) {
    int bignSum = 0;
    bign ans;

    ans.len = len;
    for (int i = 0; i < len; i++) {
        bignSum += num[i] * b;
        ans.num[i] = bignSum % 10;
        bignSum /= 10;
    }

    while (bignSum) {
        ans.num[ans.len++] = bignSum % 10;
        bignSum /= 10;
    }

    return ans;
}

bign bign::operator * (const bign& b) {
    bign ans;
    ans.len = 0; 

    for (int i = 0; i < len; i++){
        int bignSum = 0;  

        for (int j = 0; j < b.len; j++){
            bignSum += num[i] * b.num[j] + ans.num[i+j];
            ans.num[i+j] = bignSum % 10;
            bignSum /= 10;
        }
        ans.len = i + b.len;  

        while (bignSum){
            ans.num[ans.len++] = bignSum % 10;
            bignSum /= 10;
        }
    }
    return ans;
}

bign bign::operator / (const int& b) {

    bign ans;

    int s = 0;
    for (int i = len-1; i >= 0; i--) {
        s = s * 10 + num[i];
        ans.num[i] = s/b;
        s %= b;
    }

    ans.len = len;
    ans.DelZero ();
    return ans;
}

int bign::operator % (const int& b) {

    bign ans;

    int s = 0;
    for (int i = len-1; i >= 0; i--) {
        s = s * 10 + num[i];
        ans.num[i] = s/b;
        s %= b;
    }

    return s;
}

uva 10844 - Bloques(数论+高精度),布布扣,bubuko.com

时间: 2024-12-29 07:58:32

uva 10844 - Bloques(数论+高精度)的相关文章

UVA 10844 - Bloques (第二类斯特灵数)

UVA 10844 - Bloques 题目链接 题意:给定n个数字,问这n个数字能分成子集分成有几种分法 思路:一开始先想了个状态,dp[i][j]表示放i个数字,分成j个集合的方案,那么转移为,从dp[i - 1][j - 1]在多一个集合,和从dp[i - 1][j]有j个位置放,那么转移方程为dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] * j;按理说这个状态转移是没问题的,但是由于这题答案是高精度,n为900时答案高达1700多位,加上高精度运算

uva 10127 - Ones(数论)

题目链接:uva 10127 - Ones 题目大意:给出n,问说者少要多少为1才可以整除n. 解题思路:等于是高精度取模,直到余数为0为止. #include <cstdio> #include <cstring> int main () { int n; while (scanf("%d", &n) == 1) { int ans = 1, c = 1; while (c) { c = (c * 10 + 1) % n; ans++; } print

UVA 10090 - Marbles (数论)

UVA 10090 - Marbles 题目链接 题意:有两种盒子,一种代价c1,能装n1个珠子,一种代价c2,能装n2个珠子,问如何正好装n个珠子,并且使得代价最少. 思路:利用扩展欧几里得算法求出n1?x+n2?y=n的一个解(x′,y′) 就可以知道x,y的通解分别为 x=x′?n/gcd(n1,n2)+n2/gcd(n1,n2)?t y=y′?n/gac(n1,n2)?n1/gcd(n1,n2)?t 由于x > 0 && y > 0,就可以求出t的范围. 那么t越小x越

UVA 1350 - Pinary(数论+递推)

题目链接:1350 - Pinary 题意:二进制数,不能有连续的1,给定第n个数字,输出相应的二进制数 思路:先是递推,求出由n位组成的数字中有几个满足条件 dp[i] = dp[i - 1] + dp[i - 2],考虑最后一位放0和倒1位放0的情况. 然后用一个sum[i]记录满足<=i位一共的情况 接着利用二分找到给定的n > sum[i - 1],i的最大值,这个就是所求的答案的最高位. 因为如果这位放1,那么就会一共多sum[i - 1] + 1个数,那么就还需要添加n - (su

uva 1529 - Clock(数论)

题目链接:uva 1529 - Clock 题目大意:给出两个时间,问从第一个时间变成第二个时间分针会和时针重叠几次. 解题思路:两个针重叠的时间是固定的,只要处理出这些重叠的时刻,在判断说给得时间区间包含的个数即可. #include <cstdio> #include <cstring> #include <cmath> const int T = 12 * 60 * 100; const int D = 6545; int sh, sm, eh, em; int

UVA10519 - !! Really Strange !!(数论+高精度)

10519 - !! Really Strange !!(数论+高精度) 题目链接 题目大意:给你n个圆,每两个圆都有相交的部分,并且相交的两个点都唯一的,不能再和别的圆交于这点.问这样在一个矩形里的相交的n个圆可以产生多少个新的封闭图形.看图会明白的. 解题思路:规律:f(n) = f(n - 1) + 2 ?(n - 1) 最后推的 f(n) = n ? (n - 1) + 2; (n >= 1), 0的时候要特判.n本身就是个大数,结果也是个大数. 代码: import java.util

UVA 756 - Biorhythms(数论)

756 - Biorhythms 题目链接 基本就是裸的中国剩余定理. 代码: #include <stdio.h> #include <string.h> const int M = 23 * 28 * 33; const int m[3] = {23, 28, 33}; int p[3], d; int gcd(int a, int b, int &x, int &y) { if (!b) {x = 1; y = 0; return a;} int d = gc

uva 11645 - Bits(计数问题+高精度)

题目链接:uva 11645 - Bits 题目大意:给出n,问从0到n这n+1个数种,数的二进制情况下,有多少11存在. 解题思路:和uva 11038一个类型的题目,只是这道题目是对于二进制下的情况.而且高精度部分可以用两个long long数解决. #include <cstdio> #include <cstring> typedef long long ll; const int N = 100; const ll M = 1e13; ll bit (int k) { r

UVA 278 - Chess(数论)

题目链接:278 - Chess 题意:求出四种棋子最多放几个 思路:车能放行列的较小值,王隔着放,皇后根据八皇后问题可知,也是放行列最小值. 关键在于马,之前做过一题类似的,马分一行,两行,和两行以上考虑,一行就能全放,两行就隔一个田字格放,三行以上就每个马隔一个位置放. 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int t, n, m; c