1002: [FJOI2007]轮状病毒
题意就是一个 matrix-tree
但因为这里没给模数,所以我们不能欧几里得。。。
于是我打上了高精度加减乘,特么还要资瓷负数,结果就是这么长的代码了:
#include <iostream>
#include <cstring>
#include <cstdio>
#define F(i, a, b) for (int i = a; i <= b; i ++)
#define G(i, a, b) for (int i = a; i >= b; i --)
#define mem(a, b) memset(a, b, sizeof a)
#define mec(a, b) memcpy(a, b, sizeof a)
#define N 110
using namespace std;
int n; struct array { int a[N >> 1], bz; } C[N][N], tmp, ans, div, d;
bool cmp(int *a, int *b) {
if (a[0] ^ b[0]) return a[0] > b[0];
G(i, a[0], 1)
if (a[i] ^ b[i]) return a[i] > b[i];
return 1;
}
bool cmq(int *a, int *b) {
int c[N]; mec(c, a);
F(i, 1, c[0]) c[i] = a[a[0] - i + 1];
return cmp(c, b);
}
void Down(array &a, array b) {
F(i, 1, b.a[0]) {
a.a[i] = a.a[i] - b.a[i];
if (a.a[i] < 0) a.a[i] += 10, a.a[i + 1] --;
}
while (a.a[0] && !a.a[a.a[0]]) a.a[0] --;
}
void Add(array &a, array b) { a.a[0] = max(a.a[0], b.a[0]);
for (int i = 1; i <= a.a[0]; i ++) {
a.a[i] = a.a[i] + b.a[i];
a.a[i + 1] += a.a[i] / 10;
a.a[i] %= 10;
if (i == a.a[0] && a.a[i + 1]) a.a[0] ++;
}
}
void Mul(array &a, int *b) {
array c; mem(c.a, 0);
F(i, 1, a.a[0])
F(j, 1, b[0]) {
c.a[i + j - 1] += a.a[i] * b[j];
c.a[i + j] += c.a[i + j - 1] / 10;
c.a[i + j - 1] %= 10;
}
c.a[0] = a.a[0] + b[0];
while (c.a[0] && !c.a[c.a[0]]) c.a[0] --;
mec(a.a, c.a);
}
int main() {
scanf("%d", &n), ans.a[ans.a[0] = 1] = 1;
F(i, 1, n) {
C[i][i % n + 1].a[0] = C[i][(i - 2 + n) % n + 1].a[0] = C[i][i].a[0] = 1;
C[i][i].a[1] = 3, C[i][i % n + 1].a[1] = C[i][(i - 2 + n) % n + 1].a[1] = 1;
C[i][i % n + 1].bz = C[i][(i - 2 + n) % n + 1].bz = 1;
}
F(i, 1, n) {
int now = i;
F(j, i, n)
if (C[j][i].a[0]) { now =j; break; }
F(j, now + 1, n)
while (C[j][i].a[0]) {
mem(div.a, 0), mem(d.a, 0), div.bz = (C[now][i].bz ^ C[j][i].bz) ? 1 : 0;
G(k, C[j][i].a[0], 1) {
if (C[j][i].a[k] || d.a[0]) d.a[++ d.a[0]] = C[j][i].a[k];
int cnt = 0;
while (cmq(d.a, C[now][i].a)) {
int L = C[now][i].a[0];
G(p, d.a[0] - L + 1, 1) {
d.a[p] -= C[now][i].a[L - p + 1];
if (d.a[p] < 0) d.a[p] += 10, d.a[p - 1] --;
}
cnt ++;
while (d.a[0] && !d.a[d.a[0]]) d.a[0] --;
}
if (div.a[0] || cnt) {
div.a[++ div.a[0]] = cnt % 10;
if (cnt > 9) div.a[++ div.a[0]] = cnt / 10;
}
}
tmp = div;
F(i, 1, div.a[0]) div.a[i] = tmp.a[div.a[0] - i + 1];
F(k, 1, n) {
tmp = div, tmp.bz ^= C[now][k].bz, Mul(tmp, C[now][k].a);
if (tmp.bz ^ C[j][k].bz) Add(C[j][k], tmp); else {
if (cmp(C[j][k].a, tmp.a)) Down(C[j][k], tmp); else Down(tmp, C[j][k]), C[j][k] = tmp, C[j][k].bz = tmp.bz == 0;
}
}
if (!C[j][i].a[0]) break;
F(k, 1, n)
swap(C[j][k], C[now][k]);
}
Mul(ans, C[i][i].a);
}
G(i, ans.a[0], 1) printf("%d", ans.a[i]);
}
看到这么恶心的做法,就知道这题肯定还有其他的做法!!
具体思路就是根据行列式的定义去展开,然后用\(f[n]\)表示当行列式为\(n*n\)的方案数,每次展开以后得到类似的\(f[n-1],f[n-2]\),然后再求解一下.