codevs3150_Combinatorics

Recently, I was studying Rujia Liu's courseware. The chapter on combinatorics included this question, but I couldn't understand his solution, so I had to use combinatorics to do it myself.

Given a number n, find how many permutations there are so that the difference between n and the sum of the terms is greater than 0 and less than 4, and the terms in the permutation can only be π or 1. At this time, it is natural to think of enumerating the number of larger π, and using the combination number to calculate the sum, plus high precision, this problem can be AC, but because the data is large, various optimizations must be considered.

Small optimization 1: high-precision pressure position. I used long long to press 9 bits, because before the array was opened too large data could not pass. Bit pressing is indeed a good way to save time and space complexity.

Small optimization 2: When calculating the number of combinations, there is no need to recalculate every time, so there are many repetitions and it is absolutely impossible to pass. Note that in the process of enumerating the number of π, we are looking for C(k, 1), C( k, 2), C(k, 3)..., you can consider recording the last result, so that you only need to multiply a number and divide a number each time.

Optimization based on the above optimization: Since only one combination number is recorded at a time, the function of high-precision calculation can be directly changed to no return value and no need to pass high-precision variables. These two terms in common writing add a part of the time complexity, and now they can be removed.

There is one last point, although it has no effect on this question: wshjzaa said that sometimes the precision of π is not enough, so the question cannot be A, so there is a writing method double pi = 4 * atan(1), orz. (Sometimes it doesn't even help to remember π = 3.1415926535)

#include <cstdio>
#include <cmath>
#include <algorithm>
#define mod 1000000000

using namespace std;

typedef long long LL;
const double pi = 4 * atan(1);
struct node
{
    int len;
    LL l[541];
    void print()
    {
        printf("%d", l[len]);
        for (int i = len - 1; i; i--)
        printf("%09d", l[i]);
        putchar('\n');
    }
}A, B;
int n;
void mul(int b)
{
    for (int i = 1; i <= B.len; ++i)
    B.l[i] *= b;
    for (int i = 1; i <= B.len; ++i)
    {
        B.l[i+1] += B.l[i] / mod;
        B.l[i] %= mod;
    }
    while(B.l[B.len+1])
    {
        ++B.len;
        B.l[B.len+1] += B.l[B.len] / mod;
        B.l[B.len] %= mod;
    }
}
void div(int b)
{
    int flag = 0;
    LL now = 0;
    for (int i = B.len; i; i--)
    {
        (now *= mod) += B.l[i];
        B.l[i] = 0;
        if (now < b) continue;
        if (!flag)
        {
            flag = 1;
            B.len = i;
        }
        B.l[i] = now / b;
        now %= b;
    }
}
void plus()
{
    A.len = max(A.len, B.len);
    for (int i = 1; i <= A.len; ++i)
    {
        A.l[i] += B.l[i];
        A.l[i+1] += A.l[i] / mod;
        A.l[i] %= mod;
    }
    while(A.l[A.len+1])
    {
        ++A.len;
        A.l[A.len+1] += A.l[A.len] / mod;
        A.l[A.len] %= mod;
    }
}
void deal()
{
    n -= 4;
    int j = (int)(n+pi), last, num = (pi+n) / pi;
    A.l[1] = A.len = B.l[1] = B.len = 1;
    for (int i = 1; i <= num; ++i)
    {
        last = j;
        j = (int)(n+pi-i*pi);
        for (int k = last - 1; k > j; k--)
        {
            mul(k+1);
            div(i+k);
        }
        mul(j+1);
        div(i);
        plus();
    }
    A.print();
}
int main()
{
    scanf("%d", &n);
    deal();
    return 0;
}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326291904&siteId=291194637