[BZOJ 2854] civilization 高斯消元

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 2854] civilization 高斯消元相关的知识,希望对你有一定的参考价值。

题意

  给定 $n$, $A_{n\times n}, B = \left\{ b_i \right\}$ .

  解方程 $Ax = B^T$ .

 

  $n \le 200, A_{ij} \in [- {10} ^ 9, {10} ^ 9]$ .

  保证 $x_i \in [- {10} ^ {18}, {10} ^ {18}]$ .

 

分析

  大素数取模下高斯消元, 通过 CRT 进行合并.

  http://blog.csdn.net/owen_hzt/article/details/41493637

 

实现

  首先, 我们测试一下 long long 大致可以存到多少.

  long long 的最大值大约是 $9 \times {10} ^ {18}$ .

 

  我们要选取两个合适的大素数取模, 然后进行 CRT .

  保证这两个素数大于 ${10} ^ 9$ , 相乘大于 ${10} ^ {18}$ , 且不会超过 long long 的最大值.

  而且, 这两个素数要保证系数矩阵满秩.

  系数矩阵是否满秩, 必须要通过高斯消元来发现, 所以我们先准备多几个素数, 取能成功的前两个.

  我们可以写一个判断是否是素数的程序, 进行检验.

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>

inline bool Prime(int x) {
    if (x <= 1) return false;
    for (int i = 2; i * i <= x; i++)
        if (x % i == 0) return false;
    return true;
}

int main(void) {
    for (int x; ~scanf("%d", &x); )
        puts(Prime(x) ? "YES" : "NO");
    return 0;
}

  我们找到了这样几个数: 1000000007, 1000000009, 1000000021, 1000000087.

 

  最后合并答案的时候注意要写快速乘法.

  因为对于 mod 一个 long long 大小的数的操作, 直接乘会爆 long long !

 

  最终代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
using namespace std;
 
#define F(i, a, b) for (register int i = (a); i <= (b); i++)
 
#define LL long long
 
const int N = 205;
const LL P[4] = {(int)1e9+7, (int)1e9+9, (int)1e9+21, (int)1e9+87};
 
int n; LL A[N][N], B[N][4];
LL X[N][4]; int z1, z2;
 
inline LL rd(void) {
    LL f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    LL x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}
 
LL Inv(LL x, LL M) { LL res = 1; for (LL y = M-2; y > 0; y >>= 1, x = x * x % M) if (y & 1) res = res * x % M; return res; }
bool Gauss(int K) {
    LL M = P[K];
    static LL a[N][N];
    F(i, 1, n) {
        F(j, 1, n) a[i][j] = A[i][j];
        a[i][n+1] = B[i][K];
    }
     
    F(i, 1, n) {
        if (!a[i][i]) {
            bool G = false;
            for (int j = i+1; j <= n && !G; j++) if (a[j][i] > 0) {
                G = true;
                F(k, 1, n+1) swap(a[i][k], a[j][k]);
            }
            if (!G) return false;
        }
        LL R = Inv(a[i][i], M);
        F(j, 1, n) if (i != j && a[j][i] > 0) {
            LL tmp = R * a[j][i] % M;
            F(k, 1, n+1)
                a[j][k] = ((a[j][k] - a[i][k] * tmp) % M + M) % M;
        }
    }
     
    F(i, 1, n) {
        LL R = Inv(a[i][i], M);
        X[i][K] = a[i][n+1] * R % M;
    }
    return true;
}
 
inline LL Mul(LL x, LL y, LL P) {
    LL res = 0;
    for (; y > 0; y >>= 1, x = (x + x) % P)
        if (y & 1) res = (res + x) % P;
    return res;
}
inline void Print(LL X1, LL P1, LL X2, LL P2) {
    printf("%lld\n", (Mul(X1 * P2, Inv(P2 % P1, P1), P1 * P2) + Mul(X2 * P1, Inv(P1 % P2, P2), P1 * P2)) % (P1 * P2));
}
 
int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2854.in", "r", stdin);
        freopen("bzoj2854.out", "w", stdout);
    #endif
     
    n = rd();
    F(i, 1, n) {
        F(j, 1, n) A[i][j] = rd();
        static char s[50]; scanf("%s", s+1);
        for (int j = 0, L = strlen(s+1); j < 4; j++)
            F(k, 1, L) B[i][j] = (B[i][j] * 10 + s[k] - 0) % P[j];
    }
     
    z1 = z2 = -1;
    for (int k = 0; k < 4; k++) {
        if (!Gauss(k)) continue;
        if (z1 == -1) z1 = k;
        else if (z2 == -1) z2 = k;
    }
     
    F(i, 1, n)
        Print(X[i][z1], P[z1], X[i][z2], P[z2]);
     
    return 0;
}

 

  

以上是关于[BZOJ 2854] civilization 高斯消元的主要内容,如果未能解决你的问题,请参考以下文章

题解P2854 [USACO06DEC]牛的过山车Cow Roller Coaster

Bailian2854 点和正方形的关系水题

[luoguP2854] [USACO06DEC]牛的过山车Cow Roller Coaster(DP + sort)

Civil3D跟AutoCAD是什么关系

Civil3D有哪些API

AutoCAD Civil3D 2023安装图文教程