ACM 算法模板


3、匈牙利算法

/*
 * 匈牙利算法
 * 默认给定二分图
 */
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define map mmap
#define search ssearch
#define maxn (1010)
int n, m, map[maxn][maxn], from[maxn], vis[maxn];
bool search(int u)
{
    for(int v = 1; v <= n; v++) if(map[u][v] && !vis[v])
    {
        vis[v] = 1;
        if(!from[v] || search(from[v]))
        {
            from[v] = u;
            from[u] = v;
            return true;
        }
    }
    return false;
}
int main()
{
    cin >> n >> m;
    for(int i = 0, u, v; i < m; i++)
    {
        scanf("%d%d", &u, &v);
        map[u][v] = map[v][u] = 1;
    }
    int tot = 0;
    for(int i = 1; i <= n; i++) if(!from[i])
    {
        memset(vis, 0, sizeof(vis));
        if(search(i)) tot++;
    }
    cout << tot << endl;
    return 0;
}

ACM 算法模板


一、数据结构类


1、并查集

/*
 * 并查集
 * 判断图连通性,速度快过宽搜很多
 */
int father[250010 * 2], rank[250010 * 2];
void disjoint_set(int n)
{
    for(int i = 1; i <= n; i++)
        father[i] = i;
}
int find(int v)
{
    return father[v] = father[v] == v? v: find(father[v]);
}
void merge(int x, int y)
{
    int a = find(x), b = find(y);
    if(rank[a] < rank[b])
        father[a] = b;
    else
    {
        father[b] = a;
        if(rank[a] == rank[b])
            rank[a]++;
    }
}

2、st表

/*
 * st表
 * st[i][j]表示元素arr[i]开始,长度为2^j区间内的最值
 * st[i][0]为arr[i],st[i][j] = max(st[i][j-1], st[i - (1 << j-1)][j-1])
 * 求区间[l, r]内最值:
 * log2[i]代表i的对数向下取整
 * 对于长度len而言,显然2^log2[len]严格大于len的一半
 * 令k = log2[r - l + 1],则最值为max(st[l][k], st[r - (1<][k])
 */
#define maxn (55000)
int log2[maxn], st[maxn][32];
void st_prepare(int n, int *arr)
{
    log2[1] = 0;
    for(int i = 2; i <= n; i++)
    {
        log2[i] = log2[i - 1];
        if((1 << log2[i] + 1) == i)
            log2[i]++;
    }

    for(int i = n; i >= 1; i--)
    {
        st[i][0] = arr[i];
        for(int j = 1; i + (1 << j) - 1 <= n; j++)
        {
            st[i][j] = max(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
        }
    }
}
int st_query(int l, int r)
{
    int len = r - l + 1, k = log2[len];
    return max(st[l][k], st[r - (1 << k) + 1][k]);
}

3、树状数组 & 二维树状数组

树状数组

/*
 * 树状数组
 * 可对A[x]增加value,可对A[1]~A[x]区间求和
 * 相比线段树,树状数组最大的优势是节约区间(线段树一般要开4倍规模)
 */
int seg[maxn];
inline int lowbit(int x)
{
    return (x&-x);
}
void add(int x, int value, int n)
{
    for(int i = x; i <= n; i += lowbit(i))
    {
        seg[i] += value;
    }
}
int get(int x)
{
    int sum = 0;
    for(int i = x; i; i -= lowbit(i))
        sum += seg[i];
    return sum;
}

二维树状数组

/*
 * 二维树状数组
 * 可对c[x][y]增加value,可对c[1][1]到c[x][y]矩阵求和
 */
int c[maxn][maxn];
inline int lowbit(int x)
{
    return (x&-x);
}
void add(int x, int y, int value, int n)
{
    for(int i = x; i <= n; i += lowbit(i))
    {
        for(int j = y; j <= n; j += lowbit(j))
        c[i][j] += value;
    }
}
int get(int x, int y)
{
    int sum = 0;
    for(int i = x; i; i -= lowbit(i))
    {
        for(int j = y; j; j -= lowbit(j))
        sum += c[i][j];
    }
    return sum;
}

4、线段树 & 树链剖分

/*
 * 基于dfs的树链剖分 & 线段树
 */
#include 
#include 
#include 
#include 
using namespace std;
#define maxn (10010)
struct edge
{
    int a, b, c;
} e[maxn];
vector<int> son[maxn];
int fa[maxn], dep[maxn], sz[maxn], next[maxn];
void dfs1(int u, int f, int d)
{
    fa[u] = f;
    dep[u] = d;
    sz[u] = 1;
    next[u] = 0;
    for(int i = 0, v; i < son[u].size(); i++)
    if((v = son[u][i]) != f) {
        dfs1(v, u, d + 1);
        sz[u] += sz[v];
        if(sz[next[u]] < sz[v])
            next[u] = v;
    }
}
int top[maxn], w[maxn], idx[maxn], cnt;
void dfs2(int u, int tp)
{
    top[u] = tp;
    idx[u] = ++cnt;
    if(!next[u]) return ;
    dfs2(next[u], tp);
    for(int i = 0, v; i < son[u].size(); i++)
    if((v = son[u][i]) != fa[u] && v != next[u]) {
        dfs2(v, v);
    }
}
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
int seg[maxn << 2];
void build(int l, int r, int rt)
{
    if(l == r) { seg[rt] = w[l]; return; }
    int m = (l + r) >> 1;
    build(lson), build(rson);
    seg[rt] = max(seg[rt<<1], seg[rt<<1|1]);
}
void update(int x, int val, int l, int r, int rt)
{
    if(l == r) { seg[rt] = val; return; }
    int m = (l + r) >> 1;
    if(x <= m) update(x, val, lson);
    else update(x, val, rson);
    seg[rt] = max(seg[rt<<1], seg[rt<<1|1]);
}
int query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) return seg[rt];
    int m = (l + r) >> 1, ret = -1;
    if(L <= m) ret = max(ret, query(L, R, lson));
    if(R > m) ret = max(ret, query(L, R, rson));
    return ret;
}
int qtree(int u, int v, int n)
{
    int topu = top[u], topv = top[v], ans = 0;
    while(topu != topv)
    {
        // printf("while()\n");
        if(dep[topu] < dep[topv]) { swap(topu, topv); swap(u, v); }
        ans = max(query(idx[topu], idx[u], 1, n, 1), ans);
        u = fa[topu];
        topu = top[u];
    }
    if(u == v) return ans;
    if(dep[u] > dep[v]) swap(u, v);
    ans = max(ans, query(idx[next[u]], idx[v], 1, n, 1));
    return ans;
}

5、主席树

/*
 * 主席树
 * 可持久化线段树
 * T[0]预留,作为“底板”,也就是版本0
 */
#define maxn (100010)
int root[maxn], cnt;
struct seg
{
    int lson, rson, num;
} T[maxn * 40];

void update(int l, int r, int &now, int pre, int a)
{
    now = ++cnt;
    T[now] = T[pre];
    T[now].num++;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    if(a <= mid) update(l, mid, T[now].lson, T[pre].lson, a);
    else update(mid + 1, r, T[now].rson, T[pre].rson, a);
}
int query(int l, int r, int pre, int now, int k)
{
    if(l == r) { return l; }
    int mid = (l + r) >> 1, lnum = T[T[now].lson].num - T[T[pre].lson].num;
    if(k <= lnum)
        return query(l, mid, T[pre].lson, T[now].lson, k);
    else
        return query(mid + 1, r, T[pre].rson, T[now].rson, k - lnum);
}

二、字符串类


0、字符串哈希

/*
 * 自然溢出字符串哈希
 * 可用于字符串判重,或利用字符串单调性结合二分解决问题
 */
typedef unsigned long long ulint;
const ulint seed = 50009uLL;
#define maxn (100010)
ulint xp[maxn], H[maxn];
char s[maxn];
void init_xp(int n)
{
    xp[0] = 1;
    for(int i = 1; i < n; i++)
        xp[i] = xp[i-1] * seed;
}
void init_hash(int n)
{
    H[0] = s[0] - 'a' + 1;
    for(int i = 1; i < n; i++)
        H[i] = H[i-1] * seed + (ulint)(s[i] - 'a' + 1);
}
void ask_hash(int l, int r)
{
    if(l == 0) return H[r];
    return H[r] - H[l-1] * xp[r - l + 1];
}

1、manacher算法

void manacher(string& s, int *R, int n)
{
/*
 * manacher算法
 * 需要将字符串预处理成$#x#x#x#x#x#x#形式
 * 若仅求长度为奇数的回文串,最左侧添加特殊字符即可
 * 记录当前最右延伸回文半径mx和对应回文中心p
 * i若位于mx以内,则将对称位置2*p-i的回文半径的不越界部分作为i的回文半径,并且继续向右侧匹配
 * 若得到新的最右延伸回文半径,更新mx和p
 */
    int p = 0, mx = 0;
    R[0] = 1;
    for(int i = 1; i < n; i++)
    {
        if(mx > i)
            R[i] = min(R[2*p - i], mx - i);
        else R[i] = 1;
        while(s[i - R[i]] == s[i + R[i]])
            R[i]++;
        if(i + R[i] > mx)
            p = i, mx = i + R[i];
    }
    return;
}

2、kmp算法

#define maxn (300000)
int next[maxn];
vector<int> pos;
void kmp(string s1, string s2)
{
/*
 * kmp实质:对模式串的每个前缀,求出与之后缀匹配的最长真前缀长度
 * next[i]表示文本串s2在匹配样式s1[i]时首次失配后的新s1下标
 * next[i]也是与s1[i-1](已匹配部分)后缀相匹配的最长真前缀长度
 * 以上注意i要大于0,next[0]没有意义
 * 与s1[i]后缀匹配的最长真前缀长度为next[i+1]
 * 所以第一个for循环也是求s1[i]最长真前缀的过程
 */
    // step 1
    int n = s1.size();
    memset(next, 0, sizeof(int) * (n + 1));
    for(int i = 1, j; i < n; i++)
    {
        j = i; //从j处开始试配
        while(j > 0) //第一次手动失配,相当于模拟s2的失配情况
        {
            j = next[j];
            if(pattern[i] == pattern[j])
            {
                next[i + 1] = j + 1; //如果在i+1处失配,只需要从j+1处开始匹配
                break;  // next[i + 1] 为s1[i]最长真前缀长度
            }
        }
    }
    // step 2
    int m = s2.size();
    pos.clear();
    for(int i = 0, j = 0; i < m; i++)
    {
        if(s2[i] == s1[j])
        {
            j++;
        }
        else
        {
            while(j > 0) // j最多回退至0
            {
                j = next[j];
                if(s1[j] == s2[i])
                {
                    j++;
                    break;
                }
            }
        }
        if(j == n) pos.push_back(i - n + 1); // 注意s1 s2应以'\0'结尾
    }
}

3、Trie树


/*
 * Trie树
 * 一般情况下出度为26,可搜索
 * 若需要对相同字符串的插入做不同记录(比如不同id),将ed换为vector即可
 * 一个典型的用法是将数字以二进制插入trie树中,方便做异或操作
 */
#define maxn (1000000)
struct Trie
{

    int next[maxn][26], ed[maxn];
    int L, root;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            next[L][i] = -1;
        ed[L] = 0;
        return L++;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[])
    {
        int now = root;
        for(int i = 0, sz = strlen(s); i < sz; i++)
        {
            if(next[now][s[i] - 'A'] == -1)
                next[now][s[i] - 'A'] = newnode();
            now = next[now][s[i] - 'A'];
        }
        ed[now] = 1;
    }

    bool query(char s[])
    {
        int now = root;
        for(int i = 0, sz = strlen(s); i < sz; i++)
        {
            if(next[now][s[i] - 'A'] == -1)
            {
                return false;
            }
            now = next[now][s[i] - 'A'];
        }
        return ed[now] == 1;
    }

};

4、后缀数组

/*
 * 后缀数组
 * 后缀数组的倍增构造法
 * 复杂度为O(nlogn)
 */
#define maxn (1000010)
bool cmp(int *r, int a, int b, int l)
{ return r[a] == r[b] && r[a + l] == r[b + l]; }
int ta[maxn], tb[maxn], bk[maxn];
void da(int *r, int *sa, int n, int m)
{
    int i, j, p, *x = ta, *y = tb, *t;
    for(i = 0; i < m; i++) bk[i] = 0;
    for(i = 0; i < n; i++) bk[x[i] = r[i]]++;
    for(i = 1; i < m; i++) bk[i] += bk[i-1];
    for(i = 0; i < n; i++) sa[--bk[x[i]]] = i;
    for(j = 1, p = 1; p < n; j *= 2, m = p)
    {
        for(p = 0, i = n - j; i < n; i++) y[p++] = i;
        for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
        for(i = 0; i < m; i++) bk[i] = 0;
        for(i = 0; i < n; i++) bk[x[i]]++;
        for(i = 1; i < m; i++) bk[i] += bk[i-1];
        for(i = n-1; i >= 0; i--) sa[--bk[x[y[i]]]] = y[i];
        for(t = x, x = y, y = t, x[sa[0]] = 0, p = 1, i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j)? p-1: p++;
    }
}
#define rank rrank
int rank[maxn], sa[maxn], height[maxn];
void calheight(int *r, int n)
{
    for(int i = 0; i < n; i++) rank[sa[i]] = i;
    for(int k = 0, i = 0; i < n; i++)
    {
        k ? k-- : 0;
        if(rank[i] > 0)
            while(r[i + k] == r[sa[rank[i] - 1] + k])
                k++;
        height[rank[i]] = k;
    }
}

5、Aho_Corasick自动机

/*
 * AC自动机
 * 典型问题:多模式匹配
 * 构建了fail树和Trie图,并用vis标记加速的快速解法
 */
#include 
#include 
#include 
#include 
using namespace std;
#define maxn (500050)
struct Aho_Corasick
{
    int next[maxn][26], nd[maxn], fail[maxn], vis[maxn];
    int root, L;
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            next[L][i] = -1;
        nd[L] = 0;
        vis[L] = 0;
        return L++;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char *s)
    {
        int now = root;
        for(int i = 0, key, sz = strlen(s); i < sz; i++)
        {
            key = s[i] - 'a';
            if(next[now][key] == -1)
                next[now][key] = newnode();
            now = next[now][key];
        }
        nd[now]++;
    }
    void build()
    {
        // fail数组含义
        // 和i节点代表的前缀的后缀匹配的trie上最长真前缀,由trie树性质得唯一
        // 即当i节点的某边发生失配时转移到达的trie上最长真前缀
        // if(next[i][j] == -1) next[i][j] = next[fail[i]][j]
        queue<int> Q;
        fail[root] = root;
        for(int i = 0; i < 26; i++)
        if(next[root][i] == -1)
            next[root][i] = root;
        else
        {
            fail[next[root][i]] = root;
            Q.push(next[root][i]);
        }

        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0; i < 26; i++)
            if(next[now][i] == -1)
                next[now][i] = next[fail[now]][i];
            else
            {
                fail[next[now][i]] = next[fail[now]][i];
                Q.push(next[now][i]);
            }
        }
    }
    int query(char *s)
    {
        int now = root, ret = 0;
        for(int i = 0, key, tmp, sz = strlen(s); i < sz; i++)
        {
            key = s[i] - 'a';
            tmp = now = next[now][key];
            while(tmp != root && !vis[tmp])
            {
                ret += nd[tmp];
                nd[tmp] = 0;
                vis[tmp] = 1;
                tmp = fail[tmp];
            }
        }
        return ret;
    }
} actree;
char keyword[100];
char text[1000010];
int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        actree.init();

        int n;
        cin >> n;
        while(n--)
        {
            scanf("%s", keyword);
            actree.insert(keyword);
        }
        actree.build();

        scanf("%s", text);
        cout << actree.query(text) << endl;
    }
    return 0;
}

三、图论


1、spfa最短路算法

/*
 * spfa最短路算法
 * 基于队列优化加速的最短路算法
 * 复杂度为O(V*E),但一般情况下很快,速度堪比dijkstra
 */
typedef long long lint;
#define maxn (100010)
int n;
vectorint, int> > e[maxn];
lint dist[maxn];
queue<int> que;
bool inQue[maxn];
void spfa(lint dist[], int src)
{
    memset(dist, 63, sizeof(lint) * (n+1));
    dist[src] = 0;
    que.push(src);
    inQue[src] = true;
    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        for(int i = 0, v, l; i < e[u].size(); i++)
        {
            v = e[u][i].first, l = e[u][i].second;
            if(dist[u] + l < dist[v])
            {
                dist[v] = dist[u] + l;
                if(!inQue[v])
                {
                    que.push(v);
                    inQue[v] = true;
                }
            }
        }
        inQue[u] = false;
    }
}

2、dijkstra最短路算法

/*
 * dijkstra单源最短路算法
 * +堆优化
 * 注意堆默认是大根堆,定义小根堆的时候需要将符号反向
 */
typedef long long lint;
#define maxn (100010)
const lint oo = 1e16;
vectorint, int> > e[maxn << 1];
lint d1[maxn << 1], dn[maxn << 1];
bool used[maxn << 1];
struct node {
    int u; lint d;
    node(int _u, lint _d) { u = _u; d = _d; }
    bool operator< (const node& b) const
    { return d > b.d; }
};
priority_queue que;
int n, m;
void dijkstra(lint d[], int src)
{
    for(int i = 1; i <= n + m; i++)
    { d[i] = oo; used[i] = false; }
    d[src] = 0;
    que.push(node(src, 0));
    while(!que.empty())
    {
        node top = que.top(); que.pop();
        int u = top.u;
        if(used[u]) continue;   /// pick out same-id node
        used[u] = true;
        for(int i = 0; i < e[u].size(); i++)
        {
            int v = e[u][i].first;
            int l = e[u][i].second;
            if(d[u] + l < d[v])
            {
                d[v] = d[u] + l;
                que.push(node(v, d[v]));    /// may out many node having same id
            }
        }
    }
}

四、数学


1、快速幂

typedef long long lint;
lint mod;
lint quick_pow(lint a, lint n)
{
    if(!n) return 1 % mod;
    lint tmp = quick_pow(a, n >> 1);
    tmp = tmp * tmp % mod;
    if(n & 1) tmp = tmp * a % mod;
    return tmp;
}

2、矩阵快速幂

typedef long long lint;
int mod;
struct matrix
{
    int a[4][4], n;
    void clear() { memset(a, 0, sizeof(a)); }
    matrix(int k, int type)
    {
        n = k, clear();
        if(type) for(int i = 0; i < n; i++)
            a[i][i] = 1;
    }
    matrix() { n = 2, clear(); a[0][0] = a[0][1] = a[1][0] = 1, a[1][1] = 0; }
    matrix operator* (const matrix& b) const
    {
        matrix o = matrix(n, 0);
        for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
        for(int k = 0; k < n; k++)
        {
            o.a[i][j] += ((lint)a[i][k] * b.a[k][j]) % mod;
            o.a[i][j] %= mod;
        }
        return o;
    }
    friend matrix operator^ (matrix tmp, int k)
    {
        matrix o = matrix(tmp.n, 1);
        while(k)
        {
            if(k & 1) o = o * tmp;
            tmp = tmp * tmp;
            k >>= 1;
        }
        return o;
    }
};
/*
 * | A E |  | A 1 |
 * | 0 E |  | 0 1 |
 */
matrix getKthsum(const matrix& b, int k)
{
    matrix tmp = matrix(b.n << 1, 0);
    for(int i = 0; i < b.n; i++)
    for(int j = 0; j < b.n; j++)
    tmp.a[i][j] = b.a[i][j];
    for(int i = 0; i < b.n; i++)
    {
        tmp.a[i][b.n + i] = 1;
        tmp.a[b.n + i][b.n + i] = 1;
    }
    tmp = tmp^(k+1);
    matrix o = matrix(b.n, 0);
    for(int i = 0; i < b.n; i++)
    for(int j = 0; j < b.n; j++)
    o.a[i][j] = tmp.a[i][b.n + j];
    for(int i = 0; i < b.n; i++)
        o.a[i][i] = (o.a[i][i] + mod - 1) % mod;

    return o;
}

3、欧几里得算法

/*
 * 辗转相除法
 * 注意a、b不可同时为0
 */
int euclid(int a, int b) { return b == 0 ? a : gcd(b, a % b); }

4、质因数分解

/*
 * 质因数分解
 * O(sqrt(n))
 * 分结束某数的所有质因数和对应次数
 */
typedef long long lint;
void factor(lint n, lint a[], int b[], int &tot)
{
    int temp = (int)((double)sqrt(n) + 1), i;
    lint now = n;
    tot = 0;
    for(i = 2; i <= temp; i++) if(now % i == 0)
    {
        a[++tot] = i;
        b[tot] = 0;
        while(now % i == 0)
        {
            b[tot]++;
            now /= i;
        }
    }
    if(now != 1)
    {
        a[++tot] = now;
        b[tot] = 1;
    }
}

4、单调队列 & 单调栈

/*
 * 单调队列
 * two-pointers
 */
int sq[maxn], st = 0, ed = 0;   //初始化
for(int i = l; i <= r; i++) //区间[l, r]入队列
{
    while(st < ed && arr[i] > sq[ed - 1]) ed--;
    sq[ed++] = arr[i];
}
for(int i = l; i <= r; i++) //区间[l, r]出队列
{
    if(arr[i] == sq[st]) st++;
}
/*
 * 单调栈
 * 用于O(n)时间内对序列中每个元素求出其左端首个小于/大于的元素
 * 常用来解决区间问题,也出现过在后缀数组题目中优化计数问题,很神的一个结构
 */
int _top;
pair<int, int> _stack[maxn];
inline void _push_stack(int x[], int w, int p)
{
    while(_top > 0)
    {
        if(w < _stack[_top].first)
            _top--;
        else
            break;
    }
    if(!_top) x[p] = -1;
    else x[p] = _stack[_top].second;
    _stack[++_top] = make_pair(w, p);
}

其他


1、读入挂

int get()
{
    int ans = 0;
    char c;
    c = getchar();
    while( !isdigit(c) ) c = getchar();
    while( isdigit(c) ) ans = ans * 10 + c - '0' , c = getchar();
    return ans;
}

2、高精度

/*
 * 高精度加法、乘法
 * MOD用10000而不是10,增加效率,节约空间
 */
struct bign
{
    #define MAX_B (100)
    #define MOD (10000)
    int a[MAX_B], n;
    bign() { a[0] = 0, n = 1; }
    bign(int num)
    {
        n = 0;
        do {
            a[n++] = num % MOD;
            num /= MOD;
        } while(num);
    }
    bign& operator= (int num)
    { return *this = bign(num); }
    bign operator+ (const bign& b) const
    {
        bign c = bign();
        int cn = max(n, b.n), d = 0;
        for(int i = 0, x, y; i < cn; i++)
        {
            x = (n > i) ? a[i] : 0;
            y = (b.n > i) ? b.a[i] : 0;
            c.a[i] = (x + y + d) % MOD;
            d = (x + y + d) / MOD;
        }
        if(d) c.a[cn++] = d;
        c.n = cn;
        return c;
    }
    bign& operator+= (const bign& b)
    {
        *this = *this + b;
        return *this;
    }
    bign operator* (const bign& b) const
    {
        bign c = bign();
        int cn = n + b.n, d = 0;
        for(int i = 0; i <= cn; i++)
            c.a[i] = 0;
        for(int i = 0; i < n; i++)
        for(int j = 0; j < b.n; j++)
        {
            c.a[i + j] += a[i] * b.a[j];
            c.a[i + j + 1] += c.a[i + j] / MOD;
            c.a[i + j] %= MOD;
        }
        while(cn > 0 && !c.a[cn-1]) cn--;
        if(!cn) cn++;
        c.n = cn;
        return c;
    }
    friend ostream& operator<< (ostream& _cout, const bign& num)
    {
        printf("%d", num.a[num.n - 1]);
        for(int i = num.n - 2; i >= 0; i--)
            printf("%04d", num.a[i]);
        return _cout;
    }
};

你可能感兴趣的:(ACM 算法模板)