Jomoo的模板

by Jomoo

1 杂类算法

1.1 快读模板

template <typename Int>
inline Int read()       
{
    Int flag = 1;
    char c = getchar();
    while ((!isdigit(c)) && c != '-') c = getchar();
    if (c == '-') flag = -1, c = getchar();
    Int init = c & 15;
    while (isdigit(c = getchar())) init = (init << 3) + (init << 1) + (c & 15);
	return init * flag;
}

template <typename Int>
inline Int read(char &c)       
{
    Int flag = 1;
    c = getchar();
    while ((!isdigit(c)) && c != '-') c = getchar();
    if (c == '-') flag = -1, c = getchar();
    Int init = c & 15;
    while (isdigit(c = getchar())) init = (init << 3) + (init << 1) + (c & 15);
	return init * flag;
}

template <typename Int>
inline void write(Int x)
{
    if (x < 0) putchar('-'), x = ~x + 1;
    if (x > 9) write(x / 10);
    putchar((x % 10) | 48);
}  

template <typename Int>
inline void write(Int x, char nextch)
{
    write(x);
    putchar(nextch);
}

int main()
{
    return 0;
}

1.2 O(1) int64 乘法

LL mul(LL a, LL b, LL P){
    LL L = a * (b >> 25LL) % P * (1LL << 25) % P;
    LL R = a * (b & ((1LL << 25) - 1)) % P;
    return (L + R) % P;
}

2 图论算法

2.1 树类 - Trie

#define TrieNodeMax 100007 
// should @using namespace std
template <int charSetSize = 26, char base = 'a'>
struct Trie {
    bool isEndStr[TrieNodeMax];
    int son[TrieNodeMax][charSetSize], top = 1;
    bool insert(string s)
    {
        int u = 1;
        for (int i = 0; i < s.length(); i++) {
            if (!son[u][s[i] - base]) {
                son[u][s[i] - base] = ++top;
            } else if (isEndStr[son[u][s[i] - base]] || i == s.length() - 1) return 0;
            u = son[u][s[i] - base];
            if (i == s.length() - 1) isEndStr[u] = 1;
        }
        return 1;
    }
};

2.2 树类 - 并查集(NB version)

复杂度 \(O(n\alpha{(n)})\),不用辅助数组

struct UFS {
    int fa[400007];
    int familyCnt;

    UFS() : familyCnt(0)
    {
        memset(fa, -1, sizeof(fa));
    }

    int find(int u)
    {
        return fa[u] < 0 ? u : fa[u] = find(fa[u]);
    }

    void connect(int x, int y)
    {
        int xx = find(x), yy = find(y);
        if (xx == yy) return;
        if (fa[xx] > fa[yy]) swap(xx, yy);
        fa[xx] += fa[yy];
        fa[yy] = xx;
        familyCnt--;
    }

    bool isFamily(int u, int v)
    {
        return find(u) == find(v);
    }
} fam;

2.3 树类 - LCA

void dfs_LCA(int now, int depth) 
{
    use[now] = true;
    deep[now] = depth;
    for (rg int k = 1; k <= SizeLogN; k++){
        f[now][k] = f[f[now][k - 1]][k - 1];
    }
    for (rg EDGE *nxt = v[now]; nxt; nxt = nxt->next_edge) {
        if(!use[nxt->e]) {
            f[nxt->e][0] = now;
            dfs_LCA(nxt->e, depth + 1);
        }
    }
// 	use[now] = false;
} 

inline int jump(int u, int depth) {
    for (rg int k = 0; k <= SizeLogN; k++) {
        if ((depth & (1 << k))) u = f[u][k];
    }
    return u;
}

inline int LCA(int u, int v){
    if (deep[u] < deep[v]) swap(u, v);
    u = jump(u, deep[u] - deep[v]);
    for (rg int k = SizeLogN; k >= 0; k--) {
        if (f[u][k] != f[v][k]) u = f[u][k], v = f[v][k]; 
    }
    return u == v ? u : f[u][0];
}
	
f[s][0] = 0;
dfs_LCA(s, 0);
LCA(u, v);

2.4 树类 - 超级树状数组

\[sum[i]=\sum_{j=1}^ia[j]+\sum_{j=1}^idelta[j]*(i-j+1) \]

\[sum[i]=\sum_{j=1}^ia[j]+(i+1)*\sum_{j=1}^idelta[j]-\sum_{j=1}^idelta[j]*j \]

\(basicSum\) 数组维护 \(a\) 数组的前缀和
\(delta1\)\(delta2\) 两个树状数组,\(delta1\) 维护 \(delta\) 数组的和,\(delta2\) 维护\(delta[i]*i\) 的和

template <typename Int>
class super_BIT {
  private:
  	Int n;
  	Int *basicSum, *delta1, *delta2;
  	
	Int lowbit(Int x) 
	{
	    return x & (-x);
	}
	
	void arr_add(Int *arr, Int pos, Int x) 
	{
	    while (pos <= n) {
	    	arr[pos] += x;
			pos += lowbit(pos);
		}
	}
	
	Int arr_getsum(Int *arr, Int pos)
	{
	    Int sum = 0;
	    while (pos) {
			sum += arr[pos];
			pos -= lowbit(pos);
		}
	    return sum;
	}
	
	void free_space()
	{
		delete[] basicSum;
		delete[] delta1;
		delete[] delta2;
	}
  public:
  	super_BIT() 
	{
  		basicSum = NULL;
  		delta1 = NULL;
  		delta2 = NULL;
	}
  	~super_BIT() 
	{
		free_space(); 
	}
  	
  	void init(Int size, Int *arr = NULL)
  	{
  		free_space();
  		n = size;
  		basicSum = new Int[size + 1];
  		delta1 = new Int[size + 1];
  		delta2 = new Int[size + 1];
  		memset(basicSum, 0, (size + 1) * sizeof(Int));
  		memset(delta1, 0, (size + 1) * sizeof(Int));
  		memset(delta2, 0, (size + 1) * sizeof(Int));
        if (arr != NULL) {
            for (Int i = 1; i <= n; i++) {
                basicSum[i] = basicSum[i - 1] + arr[i];
            }
        }
	}
	
	void modify(Int l, Int r, Int x)
	{
	    arr_add(delta1, l, x);
		arr_add(delta1, r + 1, -x);
		arr_add(delta2, l, x * l);
		arr_add(delta2, r + 1, -x * (r + 1));
	}
	
	Int getsum(Int r)
	{
		return basicSum[r] + arr_getsum(delta1, r) * (r + 1) - arr_getsum(delta2, r);
	}
	
	Int query(Int l, Int r)
	{
	    return getsum(r) - getsum(l - 1);
	}
	
	void sample(string problem)
	{
		if (problem == "LOJ - #132") {
			Int N, Q;
			Int *a = new Int[1000001];
			N = read<Int>();
			Q = read<Int>();
			for (Int i = 1; i <= N; i++) {
				a[i] = read<Int>();
			}
			init(N, a);
			Int type, l, r, x;
			while (Q--) {
				type = read<Int>();
				if (type == 1) {
					l = read<Int>();
					r = read<Int>();
					x = read<Int>();
					modify(l, r, x);
				} else {
					l = read<Int>();
					r = read<Int>();
					write(query(l, r), 10);
				}
				debug();
			}
		} else {
			// do
		}
	}
}; 

2.5 树类 - 平衡树(STL)

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> nums;
    int q;
    scanf("%d", &q);
    while (q--) {
        int t, x;
        scanf("%d %d", &t, &x);
        if (t == 1) {
            nums.insert(upper_bound(nums.begin(), nums.end(), x), x);
        } else if (t == 2) {
            nums.erase(lower_bound(nums.begin(), nums.end(), x));
        } else if (t == 3) {
            printf("%d\n", lower_bound(nums.begin(), nums.end(), x) - nums.begin() + 1);
        } else if (t == 4) {
            printf("%d\n", nums[x - 1]);
        } else if (t == 5) {
            printf("%d\n", *--lower_bound(nums.begin(), nums.end(), x));
        } else {
            printf("%d\n", *upper_bound(nums.begin(), nums.end(), x));
        }
    }
    return 0;
}

2.6 树类 AC-Trie

2.6.1 模板 1

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

n行模式串
1行文本串

struct ACtrie {
    ACtrie *fail, *son[charSize];
    int count;
    bool found;
    int fa_sonId; // 在爸爸那里自己的ID,即本节点代表的字母
    ACtrie() : fail(NULL), count(0), found(0), fa_sonId('~' - baseChar)
    {
        memset(son, 0, sizeof(son));
    }
};

ACtrie *root = new ACtrie;

void insert(string s)
{
    ACtrie *p = root;
    for (string::iterator it = s.begin(); it != s.end(); it++) {
        if (!p->son[*it - baseChar]) {
            p->son[*it - baseChar] = new ACtrie;
            p->son[*it - baseChar]->fa_sonId = *it - baseChar;
        }
        p = p->son[*it - baseChar];
    }
    p->count++;
}

void make_fail()
{
    queue<ACtrie*> q;
    for (int i = 0; i < charSize; i++) {
        if (root->son[i]) {
            // printf("CNT 63 - %c.\n", i + baseChar);
            q.push(root->son[i]);
            root->son[i]->fail = root;
        }
    }
    while (!q.empty()) {
        ACtrie *p = q.front();
        q.pop();
        for (int i = 0; i < charSize; i++) {
            if (!p->son[i]) continue;
            ACtrie *f = p->fail;
            while (true) {
                if (f->son[i]) {
                    p->son[i]->fail = f->son[i];
                    break;
                }
                if (f == root) {
                    p->son[i]->fail = root;
                    break;
                }
                f = f->fail;
            }
            q.push(p->son[i]);
        }
    }
}

void build_ACtrie(vector<string> sArr)
{
    for (vector<string>::iterator it = sArr.begin(); it != sArr.end(); it++) {
        insert(*it);
    }
    make_fail();
}

int match_task1(string txt) // 有多少个模式串在文本串里出现过(多次出现答案只算1,重复的模式串答案算多个)
{
    ACtrie *u = root, *v;
    int ans(0);
    for (string::iterator it = txt.begin(); it != txt.end(); it++) {
        if (u->son[*it - baseChar]) u = u->son[*it - baseChar];
        else {
            while (!u->son[*it - baseChar] && u != root) {
                u = u->fail;
            }
            if (u->son[*it - baseChar]) {
                u = u->son[*it - baseChar];
            }
        }
        
        v = u;
        while (v->count && !v->found) {
            ans += v->count;
            v->found = true;
            v = v->fail;
        }
    }
    return ans;
}

int main()
{
    int n = read<int>();
    string s, txt;
    vector<string> v;
    for (int i = 1; i <= n; i++) {
        cin >> s;
        v.push_back(s);
    }
    build_ACtrie(v);
    cin >> txt;
    write(match_task1(txt), 10);
    return 0;
}

2.6.2 模板 2

有 N 个由小写字母组成的模式串以及一个文本 T 。每个模式串可能会在文本串中出现多次。你需要找出(b)哪些(/b)模式串在文本串 T 中出现的次数最多。

n行模式串
1行文本串

int TJ[150 + 7];
const int charSize = 26;
const char baseChar = 'a';

struct ACtrie {
    ACtrie *fail, *son[charSize];
    int count;
    string originalString;
    bool found;
    int inputId;
    int fa_sonId; // 在爸爸那里自己的ID,即本节点代表的字母
    ACtrie() : fail(NULL), count(0), found(0), fa_sonId('~' - baseChar)
    {
        memset(son, 0, sizeof(son));
    }
};

ACtrie *root = new ACtrie;

void insert(string s, int inputId)
{
    ACtrie *p = root;
    for (string::iterator it = s.begin(); it != s.end(); it++) {
        if (!p->son[*it - baseChar]) {
            p->son[*it - baseChar] = new ACtrie;
            p->son[*it - baseChar]->fa_sonId = *it - baseChar;
        }
        p = p->son[*it - baseChar];
    }
    p->count++;
    p->originalString = s;
    p->inputId = inputId;
}

void make_fail()
{
    queue<ACtrie*> q;
    for (int i = 0; i < charSize; i++) {
        if (root->son[i]) {
            q.push(root->son[i]);
            root->son[i]->fail = root;
        }
    }
    while (!q.empty()) {
        ACtrie *p = q.front();
        q.pop();
        for (int i = 0; i < charSize; i++) {
            if (!p->son[i]) continue;
            ACtrie *f = p->fail;
            while (true) {
                if (f->son[i]) {
                    p->son[i]->fail = f->son[i];
                    // printf("char %c:find my pFail!\n", i + baseChar);
                    break;
                }
                if (f == root) {
                    p->son[i]->fail = root;
                    break;
                }
                f = f->fail;
            }
            q.push(p->son[i]);
        }
    }
}

void build_ACtrie(vector<string> sArr)
{
    int count = 0;
    for (vector<string>::iterator it = sArr.begin(); it != sArr.end(); it++) {
        insert(*it, count++);
    }
    make_fail();
}

void match(string txt) 
{
    ACtrie *u = root, *v;
    for (string::iterator it = txt.begin(); it != txt.end(); it++) {
        if (u->son[*it - baseChar]) u = u->son[*it - baseChar];
        else {
            while (!u->son[*it - baseChar] && u != root) {
                u = u->fail;
            }
            if (u->son[*it - baseChar]) {
                u = u->son[*it - baseChar];
            }
        }
        
        v = u;
        while (v != root) {
            if (v->count) TJ[v->inputId]++;
            v = v->fail;
        }
    }
}

void clean(ACtrie *rt = root) 
{
    rt->originalString = "";
    rt->count = 0;
    rt->inputId = 0;
    rt->fail = NULL;
    for (int i = 0; i < charSize; i++) {
        if (rt->son[i]) {
            clean(rt->son[i]);
            // delete rt->son[i];
        }
    }
}

struct forSort {
    string s;
    int id;
    int val;
    bool operator < (const forSort &other) const {
        return val ^ other.val ? val > other.val : id < other.id;;
    }
} a[150 + 7];

int main()
{
    int n = read<int>();
    if (!n) return 0;
  sPosTAG:
    memset(Jalg::TJ, 0, sizeof(Jalg::TJ));
    Jalg::clean();
    string s, txt;
    vector<string> v;
    for (int i = 1; i <= n; i++) {
        cin >> s;
        v.push_back(s);
    }
    Jalg::build_ACtrie(v);
    cin >> txt;
    Jalg::match(txt);
    for (int i = 0; i < n; i++) {
        a[i] = (forSort){v[i], i, Jalg::TJ[i]};
    }
    sort(a, a + n);
    int ans = a[0].val;
    write(ans, 10); 
    int i = 0;
    while (i < n && a[i].val == ans) {
        printf("%s\n", a[i++].s.c_str());
    }
    n = read<int>();
    if (n) goto sPosTAG;
    return 0;
}

2.7 图类 - 迪杰斯特拉

struct Graph {
    struct Node {
        int u, val;
        bool operator < (const Node &other) const
        {
            return val > other.val;
        }
    };
    struct Edge {
        int v, w;
    } e[200007];
    int head[100007], next[200007], edgeCnt;

    Graph() : edgeCnt(0)
    {
        memset(head, -1, sizeof(head));
    }

    void addEdge(int u, int v, int w)
    {
        e[++edgeCnt] = (Edge){v, w};
        next[edgeCnt] = head[u];
        head[u] = edgeCnt;
    }

    void dij(int n, int s, int *dis)
    {
        memset(dis, 0x3f, sizeof(int) * (n + 1));
        dis[s] = 0;
        priority_queue<Node> q;
        q.push((Node){s, 0});
        while (!q.empty()) {
            while (q.top().val != dis[q.top().u] && !q.empty()) q.pop();
            if (q.empty()) break;
            int fr = q.top().u;
            q.pop();
            #define to e[i].v
            #define va e[i].w
            for (int i = head[fr]; ~i; i = next[i]) {
                if (dis[to] - va > dis[fr]) {
                    dis[to] = dis[fr] + va;
                    q.push((Node){to, dis[to]});
                }
            }
            #undef to
            #undef va
        }
    }
} G;

int main()
{
    int n, m, s;
    int u, v, w;
    n = read<int>();
    m = read<int>();
    s = read<int>();
    while (m--) {
        u = read<int>();
        v = read<int>();
        w = read<int>();
        G.addEdge(u, v, w);
    }
    int *dis = new int[n + 1];
    G.dij(n, s, dis);
    for (int i = 1; i <= n; i++) {
        write
        (dis[i], 32);
    }
    return 0;
}

2.8 图类 - SPFA(带卡界)判负环

struct Edge {
    int v, w;
    int nxt;
    Edge() {}
    Edge(int _v, int _w, int _nxt) : v(_v), w(_w), nxt(_nxt) {}
} edges[6007]; 
// 链式前向星存图
int top = 1;
int n, m;

int head[2007] = {0};
int dis[2007] = {0};
bool inqueue[2007] = {0};

inline void add_edge(int u, int v, int w) // 单次加边操作
{
    edges[top] = Edge(v, w, head[u]);
    head[u] = top++;
}

inline void add(int u, int v, int w) // 加边操作
{
    add_edge(u, v, w);
    if (w >= 0) add_edge(v, u, w);
}

const double K = 20.076030; // 即题解中所说的 "T"
bool SPFA_bfs()
{ 
    queue <int> q;
    q.push(1);
    inqueue[1] = 1;
    int times = 0; 
    while (!q.empty()) {
        times++;
        if (times > K * (n + m)) return 1;
        // 以上两行:卡界
        int n = q.front(); q.pop();
        inqueue[n] = 0;
        for (int i = head[n]; i != -1; i = edges[i].nxt) {
            Edge &e = edges[i];
            if (dis[e.v] > dis[n] + e.w) {
                dis[e.v] = dis[n] + e.w;
                if (!inqueue[e.v]) q.push(e.v);
            }
        }
    }
    return 0;
}

void van()
{
    n = readint();
    m = readint();
    top = 1;
    memset(head, -1, sizeof(head));
    memset(dis, 0x3f, sizeof(dis));
    memset(inqueue, 0, sizeof(inqueue));
    dis[1] = 0;
    register int ui, vi, wi;
    for (register int i = 1; i <= m; i++) {
        ui = readint();
        vi = readint();
        wi = readint();
        add(ui, vi, wi);
    }
    if (SPFA_bfs()) puts("YE5");
    else puts("N0");
}

int main()
{
    register int T = readint();
    while (T--) van();
    return 0;
}

2.9 图类 - 网络流

P2045 方格取数加强版

struct Edge {
    int u, v, w;
    int cost;
    int next;
    Edge() {}
    Edge(int _u, int _v, int _w, int _cost, int _next) : u(_u), v(_v), w(_w), cost(_cost), next(_next) {}
};

int n, k, s, t;
Edge edges[300007]; 
int head[5007], top = 0;
int could[5007];
int road[5007];
int pre[5007];

template <typename _Tp>
void queue_clear(queue<_Tp> &a)
{
    queue<_Tp> empty;
    swap(a, empty);
}
queue <int> q;

void _add_once(int u, int v, int w, int cost)
{
    edges[top] = Edge(u, v, w, cost, head[u]);
    head[u] = top++;
}

void add(int u, int v, int w, int cost)
{
    _add_once(u, v, w, cost);
    _add_once(v, u, 0, -cost);
}

// 如果你想查看一些 DEBUG ,请去掉下一行开头的注释符号
// #define TEST_OPEN
// 【警告:仅限小数据(如小样例)】 

#ifndef TEST_OPEN 
#define fprintf(...)  
#endif

int dis[10007];
bool SPFA()
{
	queue_clear(q);
    bool vis[10007] = {0};
    memset(dis, 0x3f, sizeof(dis));
    memset(could, 0x3f, sizeof(could));
    dis[s] = 0;
    vis[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        vis[now] = 0;
        for (int nNow = head[now]; nNow != -1; nNow = edges[nNow].next) {
            Edge &e = edges[nNow];
            if (e.w > 0 && dis[e.v] > dis[now] + e.cost) {
                dis[e.v] = dis[now] + e.cost;
                road[e.v] = nNow;
                could[e.v] = min(could[now], e.w);
                pre[e.v] = now;
                if (!vis[e.v]) {
                    q.push(e.v);
                    vis[e.v] = 1;
                }
            }
        }
    }
    if (dis[t] != 0x3f3f3f3f) return true; // success
    else return false; // unsuccess
}

void EK_MCMF() 
{
    // EK_MCMF : 基于 EK 的 MCMF 算法 
	//           (Edmonds Karp's "Min Cost Max Flow" algorithm)
    int maxflow = 0, mincost = 0;
#ifdef TEST_OPEN
    int count = 0;
#endif
    while (SPFA()) {
        for (int pNow = t; pNow != s; pNow = pre[pNow]) {
            edges[road[pNow]].w -= could[t];
            edges[road[pNow] ^ 1].w += could[t];
        }
        maxflow += could[t];
        mincost += dis[t] * could[t];
    }
    printf("%d", -mincost);
#ifdef TEST_OPEN
    printf("\nDUBUG:maxflow = %d.\n", maxflow);
#endif
}

enum IN_OUT {
    IN = 0, 
    OUT = 1
};

int getrank(int x, int y, IN_OUT status)
{
    return status * n * n + (x - 1) * n + y;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &k);
    s = 0;
    t = getrank(n, n, OUT) + 1;
    add(s, getrank(1, 1, IN), k, 0);
    add(getrank(n, n, OUT), t, k, 0);
    int aij;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            scanf("%d", &aij);
            add(getrank(i, j, IN), getrank(i, j, OUT), 1, -aij);
            add(getrank(i, j, IN), getrank(i, j, OUT), k - 1, 0);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < n; j++) {
            add(getrank(i, j, OUT), getrank(i, j + 1, IN), k, 0);
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 1; j <= n; j++) {
            add(getrank(i, j, OUT), getrank(i + 1, j, IN), k, 0);
        }
    }
    EK_MCMF();
    return 0;
}

3 字符串算法

3.1 KMP

int nxt[1000007];
int n, m;
char a[1000007], b[1000007]; 

void GetNext()
{
    int j = 0, k = -1;
    nxt[0] = -1;
    while (j < m) {
        if (k == -1 || b[j] == b[k]) nxt[++j] = ++k;
        else k = nxt[k];
    }
}

void Match()
{
    int j = -1, k = -1;
    while (j < n) {
        // printf("j %d k %d.\n", j, k);
        if (k == -1 || a[j] == b[k]) j++, k++;
        else k = nxt[k];
        if (k == m) write(j - m + 1, 10), k = nxt[k];
    }
}

int main()
{
    scanf("%s%s", a, b);
    n = strlen(a);
    m = strlen(b);
    GetNext();
    // for (int i = 0; i < m; i++) nxt[i]++;
    Match();
    // for (int i = 0; i < m; i++) write(nxt[i] + 1, 32);
    for (int i = 1; i <= m; i++) write(nxt[i], 32);
    return 0;
}

3.2 manacher

char str[22000007] = {'|', '^'};
int ans[22000007] = {0};

int main() 
{
    char ch;
    int len = 2;
    while ((ch = getchar()) != EOF) {
        str[len] = ch;
        len++;
        str[len] = '^';
        len++;
    }
    
    int mi_2(0), right(0);
    int maxLen = 0;
    for (int i = 1; i < len; i++) {
        ans[i] = right > i ? min(ans[mi_2 - i], right - i) : 1;
        
        while (str[i + ans[i]] == str[i - ans[i]])
            ans[i]++;
    
        if (right < i + ans[i]) {
            right = i + ans[i];
            mi_2 = i << 1;
        }

        if (maxLen < ans[i])
            maxLen = ans[i];
    }
    write(maxLen - 1);
    return 0; 
}

4 数论算法

4.1 FFT

version = fast,经典,不是我写的

#define Maxn 1350000
using namespace std;
const double Pi=acos(-1);
int n,m;
struct CP
{
  CP (double xx=0,double yy=0){x=xx,y=yy;}
  double x,y;
  CP operator + (CP const &B) const
  {return CP(x+B.x,y+B.y);}
  CP operator - (CP const &B) const
  {return CP(x-B.x,y-B.y);}
  CP operator * (CP const &B) const
  {return CP(x*B.x-y*B.y,x*B.y+y*B.x);}
}f[Maxn<<1],p[Maxn<<1];
int tr[Maxn<<1];
void fft(CP *f,bool flag)
{
  for (int i=0;i<n;i++)
    if (i<tr[i])swap(f[i],f[tr[i]]);
  //枚举区间长度 
  for(int p=2;p<=n;p<<=1){
    int len=p>>1;//待合并的长度
    CP tG(cos(2*Pi/p),sin(2*Pi/p));
    if(!flag)tG.y*=-1;//p次单位根
    for(int k=0;k<n;k+=p){//枚举起始点 
      CP buf(1,0);//遍历一个子问题并合并
      for(int l=k;l<k+len;l++){
        CP tt=buf*f[len+l];
        f[len+l]=f[l]-tt;
        f[l]=f[l]+tt;
        buf=buf*tG;
      }
    }
  }
}
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=0;i<=n;i++)scanf("%lf",&f[i].x);
  for (int i=0;i<=m;i++)scanf("%lf",&p[i].x);
  for(m+=n,n=1;n<=m;n<<=1);
  for(int i=0;i<n;i++)
    tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
  fft(f,1);fft(p,1);//DFT
  for(int i=0;i<n;++i)f[i]=f[i]*p[i];
  fft(f,0);
  for(int i=0;i<=m;++i)printf("%d ",(int)(f[i].x/n+0.49));
  return 0;
}

version=slow,基础,我写的

struct complex {
	double x, y;
	complex(double xx = 0, double yy = 0) : x(xx), y(yy) {}
	
	complex operator + (complex b)
	{
		return complex(x + b.x, y + b.y);
	}
	
	complex operator - (complex b)
	{
		return complex(x - b.x, y - b.y);
	}
	
	complex operator * (complex b)
	{
		return complex(x * b.x - y * b.y, x *b.y + y * b.x);
	}
} b[Maxn], c[Maxn];
// struct_complex and operations
int n, m, r[Maxn];

void fft(complex *f, int op)
{
	for (int i = 0; i < n; i++) {
		if (i < r[i]) {
			complex tmp = f[i];
			f[i] = f[r[i]];
			f[r[i]] = tmp;
		}
	}
	for (int p = 2; p <= n; p <<= 1) { 
	    // $ O(log_n) $
		int len = p / 2;
		complex tmp(cos(Pi / len), op * sin(Pi / len));
		for (register int k = 0; k < n; k += p) { 
		    // $ O(log_n) $
			register complex buf(1, 0);
			for (register int l = k; l < k + len; l++) { 
			    // $ O(log_n) $
				register complex tt = buf * f[len + l];
				f[len + l] = f[l] - tt;
				f[l] = f[l] + tt;
				buf = buf * tmp;
			}
		}
	}
}

int main()
{
	n = read<int>();
	m = read<int>();
	for (register int i = 0; i <= n; i++) {
		b[i].x = read<int>();
	}
	for (register int i = 0; i <= m; i++) {
		c[i].x = read<int>();
	}
	m += n; 
	n = 1;
	while (n <= m) {
		n <<= 1;
	}
	for (int i = 0; i < n; i++) {
		r[i] = (r[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0);
	}
	fft(b, 1);
	fft(c, 1);
	// DFT
	for (register int i = 0; i < n; i++) b[i] = b[i] * c[i];
	fft(b, -1);
	// IDFT
	for (register int i = 0; i <= m; i++) {
		printf("%.0f ", fabs(b[i].x) / n);
	}
	return 0;
}
posted @ 2019-11-15 19:16  航空信奥  阅读(540)  评论(0编辑  收藏  举报