AC自动机, (Aho-Corasick automaton).
AC自动机是什么?
是在Trie树上建边,形成的一个图的算法.
AC自动机用来干什么?
构建状态转移的图.(维护"路径"!!)
1. 维护路径是否可以走.
2. 维护路径的值.
如何构建AC自动机.
1. 先建立一棵Trie树.
2. 在Trie树上建我们需要的边.维护节点信息.
Solved 1 / 1 A HDU 2222 Keywords Search
题意: 给定n个模式串,然后给一个文本串,问出现了多少个文本串.
(串只有小写字母)
N <= 10000 |S|<50
|S|<1000000
分析: 裸的AC自动机题.
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e6+500;
char str[maxn];
class AC {
int next[maxn][26];
int fail[maxn];
int ed[maxn];
int last[maxn];
int qsz, root;
inline int getid(char ch) { return ch - 'a'; }
inline int newnode() {
int i;
for (i=0; i<26; ++i)
next[qsz][i] = 0;
fail[qsz] = last[qsz] = ed[qsz] = 0;
return qsz++;
}
public:
void init() {
qsz = 0;
root = newnode();
}
void insert(char s[]) {
int i, id, rt = 0, len = strlen(s);
for (i=0; i<len; ++i) {
id = getid(s[i]);
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt]++;
}
void build() {
queue<int> q;
int rt, i;
fail[root] = last[root] = rt = root;
for (i=0; i<26; ++i)
if (next[rt][i])
q.push(next[rt][i]);
while (!q.empty()) {
rt = q.front(); q.pop();
for (i=0; i<26; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
last[next[rt][i]] = ed[fail[next[rt][i]]] ? fail[next[rt][i]] : last[next[rt][i]];
q.push(next[rt][i]);
}
}
}
}
int query(char s[]) {
int rt = 0, tmp, i, len = strlen(s);
int res = 0;
for (i=0; i<len; ++i) {
tmp = next[rt][getid(s[i])];
while (tmp) {
res += ed[tmp];
ed[tmp] = 0;
tmp = last[tmp];
}
rt = next[rt][getid(s[i])];
}
return res;
}
}ac;
int main()
{
int t, n, i;
scanf("%d", &t);
while (t--) {
ac.init();
scanf("%d", &n);
for (i=0; i<n; ++i) {
scanf("%s", str);
ac.insert(str);
}
ac.build();
scanf("%s", str);
printf("%d
", ac.query(str));
}
return 0;
}
View Code
Solved 1 / 2 B HDU 2896 病毒侵袭
题意: 给定n个模式串标号为1..n m个文本串,
问每个文本串中出现模式串的标号,最后统计有出现模式串的文本串个数.
每个文本串不会出现超过3个模式串.
(注意ASCII的范围是可见字符)
1<=N<=500 20<|S|<200
1<=M<=1000 2000<|S|<10000
分析: 还是裸的AC自动机.对于每个文本串,我们可以用一个set来记录出现的模式串.
#include <set>
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1e5+500;
char str[maxn];
set<int> se[1024];
class AC {
int next[maxn][128];
int fail[maxn];
int ed[maxn];
int last[maxn];
int qsz, root;
inline int getid(char ch) { return ch - 32; }
inline int newnode() {
int i;
for (i=0; i<128; ++i)
next[qsz][i] = 0;
fail[qsz] = last[qsz] = ed[qsz] = 0;
return qsz++;
}
public:
void init() {
qsz = 0;
root = newnode();
}
void insert(char s[], int tid) {
int i, id, rt = 0, len = strlen(s);
for (i=0; i<len; ++i) {
id = getid(s[i]);
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt] = tid;
}
void build() {
queue<int> q;
int rt, i;
fail[root] = last[root] = rt = root;
for (i=0; i<128; ++i)
if (next[rt][i])
q.push(next[rt][i]);
while (!q.empty()) {
rt = q.front(); q.pop();
for (i=0; i<128; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
last[next[rt][i]] = ed[fail[next[rt][i]]] ? fail[next[rt][i]] : last[next[rt][i]];
q.push(next[rt][i]);
}
}
}
}
bool query(char s[], set<int> &se) {
int rt = 0, tmp, i, len = strlen(s);
bool ishave = false;
for (i=0; i<len; ++i) {
tmp = next[rt][getid(s[i])];
while (tmp) {
if (ed[tmp])
se.insert(ed[tmp]), ishave = true;
tmp = last[tmp];
}
rt = next[rt][getid(s[i])];
}
return ishave;
}
}ac;
int main()
{
int t, n, i;
ac.init();
scanf("%d", &n);
for (i=1; i<=n; ++i) {
scanf("%s", str);
ac.insert(str, i);
}
ac.build();
scanf("%d", &n);
int tot = 0;
for (i=1; i<=n; ++i) {
scanf("%s", str);
tot += ac.query(str, se[i]);
}
for (i=1; i<=n; ++i) {
if (se[i].empty()) continue;
printf("web %d: %d", i, *se[i].begin());
se[i].erase(se[i].begin());
for (auto it : se[i]) printf(" %d", it);
printf("
");
}
printf("total: %d
", tot);
return 0;
}
View Code
Solved 1 / 2 C HDU 3065 病毒侵袭持续中
题意: 给n个模式串, 1个文本串, 问每个模式串在文本串中出现的次数
最后输出出现过的模式串 和 出现次数.
(注意ASCII的范围是可见字符--
当然,这个题也可以处理下,然后就只有大写字母,
因为模式串只有大写字母: 文本串我们只需要把它分割,
以每一段仅由大写字母组成的作为文本串进行匹配,不过没有卡空间,就随便啦.{我没被卡})
1<=N<=1000 |S|<50
|S|<2e6
分析: 又是板子题.和上一题类似的.
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 2e6+500;
const int cmaxn = 1e5;
char str[maxn];
char ss[1024][52];
int ans[1024];
class AC {
public:
int next[cmaxn][128];
int fail[cmaxn];
int ed[cmaxn];
int last[cmaxn];
int qsz, root;
inline int getid(char ch) { return ch - 32; }
inline int newnode() {
int i;
for (i=0; i<128; ++i)
next[qsz][i] = 0;
fail[qsz] = last[qsz] = ed[qsz] = 0;
return qsz++;
}
void init() {
qsz = 0;
root = newnode();
}
void insert(char s[], int tid) {
int i, id, rt = 0, len = strlen(s);
for (i=0; i<len; ++i) {
id = getid(s[i]);
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt] = tid;
}
void build() {
queue<int> q;
int rt, i;
fail[root] = last[root] = rt = root;
for (i=0; i<128; ++i)
if (next[rt][i])
q.push(next[rt][i]);
while (!q.empty()) {
rt = q.front(); q.pop();
for (i=0; i<128; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
last[next[rt][i]] = ed[fail[next[rt][i]]] ? fail[next[rt][i]] : last[next[rt][i]];
q.push(next[rt][i]);
}
}
}
}
int query(char s[]) {
int rt = 0, tmp, i, len = strlen(s);
for (i=0; i<len; ++i) {
rt = tmp = next[rt][getid(s[i])];
while (tmp) {
if (ed[tmp])
ans[ed[tmp]]++;
tmp = last[tmp];
}
}
}
}ac;
int main()
{
int t, n, i;
while (~scanf("%d", &n)) {
ac.init();
memset(ans, 0, sizeof(ans));
for (i=1; i<=n; ++i) {
scanf("%s", ss[i]);
ac.insert(ss[i], i);
}
ac.build();
scanf("%s", str);
ac.query(str);
for (i=1; i<=n; ++i) if (ans[i])
printf("%s: %d
", ss[i], ans[i]);
}
return 0;
}
View Code
Solved 1 / 7 D ZOJ 3430 Detect the Virus
题意: 给定n个Base编码后的模式串,m个Base编码的文本串,
输出在文本串中出现的模式串的个数.
0 <= N <= 512 1 <= M <= 128
分析: 将编码解码后就是一道裸的AC自动机的题了.
#include <cstdio>
#include <queue>
#include <map>
#include <set>
using namespace std;
map<int, int> ma;
int pwr[] = {1, 2, 4, 8, 16, 32, 64, 128};
void init() {
int i, id = 0;
for (i='A'; i<='Z'; ++i)
ma[i] = id++;
for (i='a'; i<='z'; ++i)
ma[i] = id++;
for (i='0'; i<='9'; ++i)
ma[i] = id++;
ma['+'] = id++;
ma['/'] = id++;
}
char str[100086];
int bits[100086];
int ssss[100086];
int get(char s[]) {
int i, j, now = 0, cnt = 0, len = 0;
for (i=0; s[i]; ++i) {
if (s[i] == '=') cnt++;
else for (j=0; j<6; ++j) bits[++now] = ma[s[i]] & (1 << (5 - j)) ? 1 : 0;
}
len = i;
now -= cnt * 2;
len = now / 8;
now = 0;
int tlen = 0, tmp;
for (i=0; i<len; ++i) {
tmp = 0;
for (j=0; j<8; ++j)
tmp += bits[++now] * pwr[7-j];
ssss[tlen++] = tmp;
}
return tlen;
}
const int maxn = 50000;
class AC {
int next[maxn][256];
int fail[maxn];
int ed[maxn];
int last[maxn];
int qsz, root;
inline int newnode() {
int i;
for (i=0; i<256; ++i)
next[qsz][i] = 0;
fail[qsz] = last[qsz] = ed[qsz] = 0;
return qsz++;
}
public:
void init() {
qsz = 0;
root = newnode();
}
void insert(int s[], int len) {
int i, id, rt = 0;
for (i=0; i<len; ++i) {
id = s[i];
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt]++;
}
void build() {
int i, rt, id;
queue<int> q;
rt = root;
fail[root] = last[root] = rt = root;
for (i=0; i<256; ++i)
if (next[rt][i])
q.push(next[rt][i]);
while (!q.empty()) {
rt = q.front(); q.pop();
for (i=0; i<256; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
q.push(next[rt][i]);
last[next[rt][i]] = ed[fail[next[rt][i]]] ?
fail[next[rt][i]] :
last[next[rt][i]];
}
}
}
}
int query(int s[], int len) {
int rt = 0, tmp, i;
int res = 0;
set<int> vis;
for (i=0; i<len; ++i) {
tmp = next[rt][s[i]];
while (tmp) {
if (ed[tmp]) {
if (vis.find(tmp) == vis.end())
vis.insert(tmp);
}
tmp = last[tmp];
}
rt = next[rt][s[i]];
}
for (set<int>::iterator iter=vis.begin(); iter!=vis.end(); ++iter) res += ed[*iter];
return res;
}
}ac;
int main()
{
// freopen("E:\input.txt", "r", stdin);
int i, n, len;
bool flag = true;
init();
while (~scanf("%d", &n)) {
ac.init();
for (i=0; i<n; ++i) {
scanf("%s", str);
len = get(str);
ac.insert(ssss, len);
}
ac.build();
scanf("%d", &n);
for (i=0; i<n; ++i) {
scanf("%s", str);
len = get(str);
printf("%d
", ac.query(ssss, len));
}
printf("
");
}
return 0;
}
View Code
Solved 1 / 1 E POJ 2778 DNA Sequence
题意: 给定m个由ATGC组成的模式串,
问一个长度为n的由ATGC组成的串不含任何一个模式串的种类数.
(0 <= m <= 10), |S|<10
n (1 <= n <=2000000000)
分析:
如果n比较小的情况下:
我们可以先建立AC自动机,然后建模式串的末尾节点标记,
同时他们的fail指针也进行标记.(被标记的节点说明是不可走的.)
然后我们从根节点出发,如果下个节点是标记过的节点,
那么说明是不可走的,我们就跳过他.然后继续走.
最后当我们走到长度为n时,我们的答案也出来了.
----> 我们在走的过程中累加答案,
dp[length][state] 表示在长度为length,状态为state下的方案数.
dp[length+1][nex_state] += dp[length][state];
最后答案就是: sigma(dp[n][0...qsz]) , qsz是状态的总数.
但是,这道题的n非常大.
所以我们需要考虑一些加速的办法. n有2e9. 可以用矩阵快速幂来加速.
我们知道,
对于一个邻接矩阵A(离散数学上有,在矩阵那一章.),
A^0表示走长度为0的方案数,
A^1表示走长度为1的方案数,
....
A^n表示走长度为n的发案数.
例如从点1出发到点10走n步 那么答案应该是 T = (A^n) ans = T[1][10];
所以我们将我们可以走到的状态构建成一个邻接矩阵,然后快速幂.
最后答案就是sigma(A[0][0..qsz])
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
typedef long long ll;
const ll mod = 100000;
class Matrix {
public:
int r, c;
ll mat[128][128];
ll *operator [] (int x) { return mat[x]; }
Matrix operator * (const Matrix &a) const {
Matrix res;
res.r = r; res.c = a.c;
int i, j, k;
for (i=0; i<res.r; ++i) {
for (j=0; j<res.c; ++j) {
res[i][j] = 0;
for (k=0; k<c; ++k)
res[i][j] = (res[i][j] + mat[i][k] * a.mat[k][j]) % mod;
}
}
return res;
}
}mt;
Matrix pwr(const Matrix &a, int k) {
Matrix base = a, r;
int i, j;
r.r = a.r; r.c = a.c;
for (i=0; i<r.r; ++i)
for (j=0; j<r.c; ++j)
r[i][j] = i==j;
while (k) {
if (k & 1) r = r * base;
base = base * base;
k >>= 1;
}
return r;
}
class AC {
public:
int next[256][4];
int ed[256];
int fail[256];
int qsz, root;
inline int getid(char ch) {
int res;
switch (ch) {
case 'A': res = 0; break;
case 'C': res = 1; break;
case 'G': res = 2; break;
case 'T': res = 3; break;
}
return res;
}
inline int newnode() {
int i;
for (i=0; i<4; ++i)
next[qsz][i] = 0;
ed[qsz] = fail[qsz] = 0;
return qsz++;
}
void init() {
qsz = 0;
root = newnode();
}
void insert(char s[]) {
int i, id, rt = 0, len = strlen(s);
for (i=0; i<len; ++i) {
id = getid(s[i]);
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt]++;
}
void build() {
int rt, i;
queue<int> q;
rt = fail[root] = 0;
for (i=0; i<4; ++i) {
if (next[rt][i])
q.push(next[rt][i]);
}
while (!q.empty()) {
rt = q.front(); q.pop();
if (ed[rt]) { }
if (ed[fail[rt]]) ed[rt] = 1;
for (i=0; i<4; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
q.push(next[rt][i]);
}
}
}
}
void make() {
memset(&mt, 0, sizeof(Matrix));
int i, j;
mt.r = mt.c = qsz;
for (i=0; i<qsz; ++i) {
for (j=0; j<4; ++j) {
if (ed[next[i][j]]) continue;
mt[i][next[i][j]]++;
}
}
}
}ac;
char str[16];
int main()
{
// freopen("E:\input.txt", "r", stdin);
int i, n, m;
while (~scanf("%d%d", &m, &n)) {
memset(&mt, 0, sizeof(mt));
ac.init();
for (i=1; i<=m; ++i) {
scanf("%s", str);
ac.insert(str);
}
ac.build();
ac.make();
mt = pwr(mt, n);
int res = 0;
for (i=0; i<ac.qsz; ++i) res = (res + mt[0][i] + mod) % mod;
printf("%d
", res);
}
return 0;
}
View Code
Solved 1 / 1 F HDU 2243 考研路茫茫――单词情结
题意: 给定n个模式串,问长度为1...L中的串出现任一模式串的个数.
0<n<6 |S|<=5
0<L<2^31
分析: 从上一题我们知道如何求 不出现模式串 长度为n的串 有多少种.
而这个题是要我们求 出现任一个模式串的文本串的个数.
我们先考虑长度为n的串有多少种可能:
很明显 出现任一模式串的文本串个数 = 文本串种类数 - 没出现任一模式串的文本串个数.
所以我们就可以套用上一题的解法,把 没出现任一模式串的文本串个数 求出.
所以对于长度为n的,我们答案res_n已经求出了.
因此 文本串长度从1...n的答案就是 res = res_1 + res_2 + res_3 + ... + res_n;
但是, n非常大! 2^31, 如果只求一个,我们可以很快求出,如果求多个,我们复杂度得乘以一个n.
明显是不可行的.
但是,我们是通过矩阵实现的.所以我们先按照矩阵的写法把答案写出:
Ans = A^1 + A^2 + A^3 + A^4 + ... + A^n;
我们现在的问题转化成了, 如何快速的求出 A^1 + A^2 + A^3 + A^4 + ... + A^n 这个式子了.
我们可以二分求和: 具体百度..或者看代码..一下就懂了.
Matrix get(Matrix mat, int k) {
if (k == 1) return mat;
if (k & 1) return get(mat, k-1) + pwr(mat, k);
else return (pwr(mat, k / 2) + pwr(mat, 0)) * get(mat, k / 2);
// 注意对于矩阵,这儿用pwr(mat, 0)而不是把式子拆开.
}
(听说也可以在矩阵上添加改改然后可以求出.但是我不会.)
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
typedef unsigned long long ull;
class Matrix {
public:
int r, c;
ull mat[32][32];
ull *operator [] (int x) { return mat[x]; }
Matrix operator * (const Matrix &a) const {
Matrix res;
res.r = r; res.c = a.c;
int i, j, k;
for (i=0; i<res.r; ++i) {
for (j=0; j<res.c; ++j) {
res[i][j] = 0;
for (k=0; k<c; ++k)
res[i][j] = (res[i][j] + mat[i][k] * a.mat[k][j]);
}
}
return res;
}
Matrix operator + (const Matrix &a) const {
Matrix res;
res.r = r; res.c = a.c;
int i, j;
for (i=0; i<res.r; ++i)
for (j=0; j<res.c; ++j)
res[i][j] = (mat[i][j] + a.mat[i][j]);
return res;
}
}mt;
Matrix pwr(const Matrix &a, int k) {
Matrix base = a, r;
int i, j;
r.r = a.r; r.c = a.c;
for (i=0; i<r.r; ++i)
for (j=0; j<r.c; ++j)
r[i][j] = i==j;
while (k) {
if (k & 1) r = r * base;
base = base * base;
k >>= 1;
}
return r;
}
Matrix get(Matrix mat, int k) {
if (k == 1) return mat;
if (k & 1) return get(mat, k-1) + pwr(mat, k);
else return (pwr(mat, k / 2) + pwr(mat, 0)) * get(mat, k / 2);
}
ull pwr4(ull k) {
ull base = 26*1llu, r = 1;
while (k) {
if (k & 1) r *= base;
base *= base;
k >>= 1;
}
return r;
}
ull get(ull mat, ull k) {
if (k == 1) return mat;
if (k & 1) return get(mat, k-1) + pwr4(k);
else return (pwr4(k / 2) + pwr4(0)) * get(mat, k / 2);
}
class AC {
public:
int next[128][26];
int ed[128];
int fail[128];
int qsz, root;
inline int getid(char ch) {
return ch - 'a';
}
inline int newnode() {
int i;
for (i=0; i<26; ++i)
next[qsz][i] = 0;
ed[qsz] = fail[qsz] = 0;
return qsz++;
}
void init() {
qsz = 0;
root = newnode();
}
void insert(char s[]) {
int i, id, rt = 0, len = strlen(s);
for (i=0; i<len; ++i) {
id = getid(s[i]);
if (!next[rt][id]) next[rt][id] = newnode();
rt = next[rt][id];
}
ed[rt]++;
}
void build() {
int rt, i;
queue<int> q;
rt = fail[root] = 0;
for (i=0; i<26; ++i)
if (next[rt][i])
q.push(next[rt][i]);
while (!q.empty()) {
rt = q.front(); q.pop();
if (ed[fail[rt]]) ed[rt] = 1;
for (i=0; i<26; ++i) {
if (!next[rt][i]) next[rt][i] = next[fail[rt]][i];
else {
fail[next[rt][i]] = next[fail[rt]][i];
q.push(next[rt][i]);
}
}
}
}
void make() {
memset(&mt, 0, sizeof(Matrix));
int i, j;
mt.r = mt.c = qsz;
for (i=0; i<qsz; ++i) {
for (j=0; j<26; ++j) {
if (ed[next[i][j]]) continue;
mt[i][next[i][j]]++;
}
}
}
}ac;
char str[16];
int main()
{
// freopen("E:\input.txt", "r", stdin);
int i, n;
ull m;
while (cin >> n >> m) {
memset(&mt, 0, sizeof(mt));
ac.init();
for (i=1; i<=n; ++i) {
scanf("%s", str);
ac.insert(str);
}
ac.build();
ac.make();
mt = get(mt, m);
ull res = get(26*1llu, m);
for (i=0; i<ac.qsz; ++i) res -= mt[0][i];
cout << res << endl;
}
return 0;
}
View Code
Solved 1 / 1 G POJ 1625 Censored!
题意: 有n个字符的字符集, p个禁止串(禁止出现的串),
问一个长度为m的串不含禁止串的种类数.
1 <= N <= 50
1 <= M <= 50
0 <= P <= 10 |S|<=10
分析: 我们发现和E题就是同一个题. 但是!!!! 这个题,n特别小.
所以,我们可以dp做,开心不?~~ 还有更开心的.这个题不用取模?
2333 真的太贴心了不用取模.....2333
什么意思呢? 你可以直接搞......才怪...你需要用大数....
因为大数太耗内存了...用矩阵会炸,但是可以用dp做,参考上面E题的思路.然后套上大数板子就可以了.
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
#define MAX_L 90
class bign
{
public:
int len, s[MAX_L];
bign();
bign(const char*);
bign(int);
bool sign;
string toStr() const;
friend istream& operator>>(istream &,bign &);
friend ostream& operator<<(ostream &,bign &);
bign operator=(const char*);
bign operator=(int);
bign operator=(const string);
bool operator>(const bign &) const;
bool operator>=(const bign &) const;
bool operator<(const bign &) const;
bool operator<=(const bign &) const;
bool operator==(const bign &) const;
bool operator!=(const bign &) const;
bign operator+(const bign &) const;
bign operator++();
bign operator++(int);
bign operator+=(const bign&);
bign operator-(const bign &) const;
bign operator--();
bign operator--(int);
bign operator-=(const bign&);
bign operator*(const bign &)const;
bign operator*(const int num)const;
bign operator*=(const bign&);
bign operator/(const bign&)const;
bign operator/=(const bign&);
bign operator%(const bign&)const;
bign factorial()const;
bign Sqrt()const;
bign pow(const bign&)const;
void clean();
~bign();
};
#define max(a,b) a>b ? a : b
#define min(a,b) a<b ? a : b
bign::bign()
{
memset(s, 0, sizeof(s));
len = 1;
sign = 1;
}
bign::bign(const char *num)
{
*this = num;
}
bign::bign(int num)
{
*this = num;
}
string bign::toStr() const
{
string res;
res = "";
for (int i = 0; i < len; i++)
res = (char)(s[i] + '0') + res;
if (res == "")
res = "0";
if (!sign&&res != "0")
res = "-" + res;
return res;
}
istream &operator>>(istream &in, bign &num)
{
string str;
in>>str;
num=str;
return in;
}
ostream &operator<<(ostream &out, bign &num)
{
out<<num.toStr();
return out;
}
bign bign::operator=(const char *num)
{
memset(s, 0, sizeof(s));
char a[MAX_L] = "";
if (num[0] != '-')
strcpy(a, num);
else
for (int i = 1, tlen = strlen(num); i < tlen; i++)
a[i - 1] = num[i];
sign = !(num[0] == '-');
len = strlen(a);
for (int i = 0, tlen = strlen(a); i < tlen; i++)
s[i] = a[len - i - 1] - 48;
return *this;
}
bign bign::operator=(int num)
{
char temp[MAX_L];
sprintf(temp, "%d", num);
*this = temp;
return *this;
}
bign bign::operator=(const string num)
{
const char *tmp;
tmp = num.c_str();
*this = tmp;
return *this;
}
bool bign::operator<(const bign &num) const
{
if (sign^num.sign)
return num.sign;
if (len != num.len)
return len < num.len;
for (int i = len - 1; i >= 0; i--)
if (s[i] != num.s[i])
return sign ? (s[i] < num.s[i]) : (!(s[i] < num.s[i]));
return !sign;
}
bool bign::operator>(const bign&num)const
{
return num < *this;
}
bool bign::operator<=(const bign&num)const
{
return !(*this>num);
}
bool bign::operator>=(const bign&num)const
{
return !(*this<num);
}
bool bign::operator!=(const bign&num)const
{
return *this > num || *this < num;
}
bool bign::operator==(const bign&num)const
{
return !(num != *this);
}
bign bign::operator+(const bign &num) const
{
if (sign^num.sign)
{
bign tmp = sign ? num : *this;
tmp.sign = 1;
return sign ? *this - tmp : num - tmp;
}
bign result;
result.len = 0;
int temp = 0;
for (int i = 0; temp || i < (max(len, num.len)); i++)
{
int t = s[i] + num.s[i] + temp;
result.s[result.len++] = t % 10;
temp = t / 10;
}
result.sign = sign;
return result;
}
bign bign::operator++()
{
*this = *this + 1;
return *this;
}
bign bign::operator++(int)
{
bign old = *this;
++(*this);
return old;
}
bign bign::operator+=(const bign &num)
{
*this = *this + num;
return *this;
}
bign bign::operator-(const bign &num) const
{
bign b=num,a=*this;
if (!num.sign && !sign)
{
b.sign=1;
a.sign=1;
return b-a;
}
if (!b.sign)
{
b.sign=1;
return a+b;
}
if (!a.sign)
{
a.sign=1;
b=bign(0)-(a+b);
return b;
}
if (a<b)
{
bign c=(b-a);
c.sign=false;
return c;
}
bign result;
result.len = 0;
for (int i = 0, g = 0; i < a.len; i++)
{
int x = a.s[i] - g;
if (i < b.len) x -= b.s[i];
if (x >= 0) g = 0;
else
{
g = 1;
x += 10;
}
result.s[result.len++] = x;
}
result.clean();
return result;
}
bign bign::operator * (const bign &num)const
{
bign result;
result.len = len + num.len;
for (int i = 0; i < len; i++)
for (int j = 0; j < num.len; j++)
result.s[i + j] += s[i] * num.s[j];
for (int i = 0; i < result.len; i++)
{
result.s[i + 1] += result.s[i] / 10;
result.s[i] %= 10;
}
result.clean();
result.sign = !(sign^num.sign);
return result;
}
bign bign::operator*(const int num)const
{
bign x = num;
bign z = *this;
return x*z;
}
bign bign::operator*=(const bign&num)
{
*this = *this * num;
return *this;
}
bign bign::operator /(const bign&num)const
{
bign ans;
ans.len = len - num.len + 1;
if (ans.len < 0)
{
ans.len = 1;
return ans;
}
bign divisor = *this, divid = num;
divisor.sign = divid.sign = 1;
int k = ans.len - 1;
int j = len - 1;
while (k >= 0)
{
while (divisor.s[j] == 0) j--;
if (k > j) k = j;
char z[MAX_L];
memset(z, 0, sizeof(z));
for (int i = j; i >= k; i--)
z[j - i] = divisor.s[i] + '0';
bign dividend = z;
if (dividend < divid) { k--; continue; }
int key = 0;
while (divid*key <= dividend) key++;
key--;
ans.s[k] = key;
bign temp = divid*key;
for (int i = 0; i < k; i++)
temp = temp * 10;
divisor = divisor - temp;
k--;
}
ans.clean();
ans.sign = !(sign^num.sign);
return ans;
}
bign bign::operator/=(const bign&num)
{
*this = *this / num;
return *this;
}
bign bign::operator%(const bign& num)const
{
bign a = *this, b = num;
a.sign = b.sign = 1;
bign result, temp = a / b*b;
result = a - temp;
result.sign = sign;
return result;
}
bign bign::pow(const bign& num)const
{
bign result = 1;
for (bign i = 0; i < num; i++)
result = result*(*this);
return result;
}
bign bign::factorial()const
{
bign result = 1;
for (bign i = 1; i <= *this; i++)
result *= i;
return result;
}
void bign::clean()
{
if (len == 0) len++;
while (len > 1 && s[len - 1] == '