ACM模板

1.AC自动机:

UVALive 3942

题目描述:

给一个字符串集合,从这个字符串集合中选出一部分字符串凑另一个长字符串。每个字符串可以选多次。有多少种方案。

比如:
s = abcd
4个单词
abc
cd
ab
abcd

就有两种方案 abcd  or   ab+cd

代码:

#include <bits/stdc++.h>
#define _xx ios_base::sync_with_stdio(0);cin.tie(0);
using namespace std;
const int MAXN = 4000*105;
typedef long long ll;
int tot;
ll dp[MAXN];
struct Node {
    int child[26];
    int flag, fail;
    int len;              //当前结点字符串的长度
    bool danger;
    void init() {
        memset(child, -1, sizeof child);
        flag = 0;
        fail = -1;
        len = 0;
        danger = false;     //当前结点是否危险
    }
}node[MAXN];
/*
 * 向tire树中加入一个字符串
 */
void add(string& s) {
    int p = 0;
    for(int i = 0; i < s.size(); i++) {
        int index = s[i] - 'a';
        int l = node[p].len;
        if(node[p].child[index] == -1) {
            node[p].child[index] = ++tot;
            p = tot;
            node[p].init();
            node[p].len = l + 1;
        }
        else p = node[p].child[index];
    }
    node[p].flag++;
    node[p].danger = true;
}
/*
 * 计算fail指针,将tire树变为tire图
 */
void getfail() {
    queue<int> que;
    que.push(0);
    while(!que.empty()) {
        int now = que.front();
        que.pop();
        for(int i = 0; i < 26; i++) {
            int& to = node[now].child[i];
            int& res = node[to].fail;
            if(to != -1) {
                int p = node[now].fail;
                while(p != -1 && node[p].child[i] == -1) p = node[p].fail;
                if(p == -1) res = 0;
                else res = node[p].child[i];
                que.push(to);
                node[to].danger = node[to].danger || node[res].danger;
            }
            else {
                if(now == 0) {
                    to = 0;
                }
                else to = node[node[now].fail].child[i];
            }
        }
    }
}
/*
 * 跑自动机+dp得到答案
 */
void getans(string& s) {
    int p = 0;
    for(int i = 0; i < s.size(); i++) {
        int index = s[i] - 'a';
        p = node[p].child[index];
        int temp = p;
        while(temp != -1 && node[temp].danger) {
            int l = node[temp].len;
            dp[i + 1] += dp[i + 1 - l]*node[temp].flag;
            dp[i + 1] %= 20071027;
            temp = node[temp].fail;
        }
    }
}
/*
 * 初始化AC自动机
 */
void initAc_Auto() {
    tot = 0;
    node[0].init();
}
int main() {
_xx
    string s, s1;
    int T = 0;
    while(cin >> s) {
        int n;
        cin >> n;
        initAc_Auto();
        for(int i = 0; i < n; i++) {
            cin >> s1;
            add(s1);
        }
        getfail();
        memset(dp, 0, sizeof dp);
        dp[0] = 1;
        getans(s);
        cout << "Case " << ++T << ": " << dp[s.size()] << endl;
    }
    return 0;
}
注:此题就题目而言可以直接用tire树dp做(不用ac自动机)62ms,也可以hash暴力dp做1800ms,看了别人的代码,真心觉得这种题有一万种ac方法,而我一种都不会!!!


2.扩展中国剩余定理

ll exgcd(ll a, ll b, ll& x, ll& y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll gcd = exgcd(b, a%b, x, y);
    ll res = x;
    x = y;
    y = res - a/b*y;
    return gcd;
}
ll lcm(ll a, ll b, ll gcd) {
    return a/gcd*b;
}
/*
 * 计算 x = a[i] mod m[i], 一共len个方程,下标从0开始
 */
ll exchina(ll a[], ll m[], ll len) {
    ll x0 = a[0], mod = m[0];
    for(int i = 1; i < len; i++) {
        ll k1, k0, r = a[i] - x0;
        ll gcd = exgcd(m[i], mod, k1, k0);
        if((a[i] - x0)%gcd != 0) return -1;
        k0 = r/gcd*k0;
        ll res = m[i]/gcd;
        k0 = (k0%res + res)%res;
        x0 = x0 + k0*mod;
        mod = lcm(mod, m[i], gcd);
        x0 %= mod;
    }
    return x0;
}

3.LCA(dfs序 + RMQ)

#include <bits/stdc++.h>
#define _xx ios_base::sync_with_stdio(0);cin.tie(0);
#define mem(a, b) memset(a, b, sizeof a);
using namespace std;
typedef long long ll;
const int INFS = 0x3fffffff;
const ll INFB = 0x3fffffffffffffff;
const int MAXN = 100005;
vector<vector<int> > v;
int label[MAXN];        //队每个节点重新编号
vector<int> df;         //dfs序
int fir[MAXN];
int dp[3*MAXN][32];
int t = 0;              //初始化时间戳
int nsize[MAXN];
int dfs(int id, int w) {
    label[id] = t++;
    int nowid = label[id];
    df.push_back(nowid);
    fir[nowid] = df.size() - 1;
    fz[nowid] = w;
    int sz = 1;
    for(int i = 0; i < v[id].size(); i++) {
        if(w == -1) sz += dfs(v[id][i], i);
        else sz += dfs(v[id][i], w);
        df.push_back(nowid);
    }
    if(sz != 1) sz--;
    return nsize[nowid] = sz;
}
void rmq() {
    int n = df.size();
    for(int i = 0; i < n; i++) {
        dp[i][0] = df[i];
    }
    for(int j = 1; (1<<j) < n; j++) {
        for(int i = 0; i + (1<<j) - 1 < n; i++) {
            dp[i][j] = min(dp[i][j - 1], dp[i + (1<<(j - 1))][j - 1]);
        }
    }
}
int getans(int l, int r) {
    int k = log2(r - l + 1.0005);
    return min(dp[l][k], dp[r - (1<<k) + 1][k]);
}

4.艾教的线段树模板(区间修改,区间查询)


#include <iostream>
#define N 10000005
#define lson (id<<1)
#define rson ((id<<1)|1)
#define mid ((l+r)>>1)
using namespace std;
struct nod{
	int sum,lazy;
}tree[N*5];
int n,q;
void push_up(int id)
{
	tree[id].sum=tree[lson].sum+tree[rson].sum;
	return;
}
void build_tree(int id,int l,int r)
{
//	cout<<id<<' '<<l<<' '<<r<<' '<<mid<<endl;
	if (l==r)
	{
		scanf("%d",&tree[id].sum);
		tree[id].lazy=0;
		return;
	}
	build_tree(lson,l,mid);
	build_tree(rson,mid+1,r);
	push_up(id);
	tree[id].lazy=0;
	return;
}

void push_down(int id,int l,int r)
{
	tree[lson].sum+=(mid-l+1)*tree[id].lazy;
	tree[lson].lazy+=tree[id].lazy;
	tree[rson].sum+=(r-mid)*tree[id].lazy;
	tree[rson].lazy+=tree[id].lazy;
	tree[id].lazy=0;
	return;
}

void ins(int id,int l,int r,int ql,int qr,int tt)
{
	if (ql<=l && r<=qr)
	{
		tree[id].sum+=(r-l+1)*tt;
		tree[id].lazy+=tt;
		return;
	}
	if (tree[id].lazy) push_down(id,l,r);
	if (ql<=mid)
		ins(lson,l,mid,ql,qr,tt);
	if (mid+1<=qr)
		ins(rson,mid+1,r,ql,qr,tt);
	push_up(id);
	return;
}

int query(int id,int l,int r,int ql,int qr)
{
	if (ql<=l && r<=qr)
	{
		return tree[id].sum;
	}
	if (tree[id].lazy)
		push_down(id,l,r);
	int sum=0;
	if (ql<=mid)
		sum+=query(lson,l,mid,ql,qr);
	if (mid+1<=qr)
		sum+=query(rson,mid+1,r,ql,qr);
	return sum;
}

大数:支持加、减、乘(大数*int)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
typedef long long ll;
const int MAXN = 10005;
ll SCALE = 1e9;
struct BigNum {
    ll value[1005];
    int len;
    BigNum() {
        memset(value, 0, sizeof value);
        len = 1;
    }
    BigNum(ll x) {
        memset(value, 0, sizeof value);
        len = 0;
        if(x == 0) len = 1;
        while(x) {
            value[len] = x%SCALE;
            x /= SCALE;
            len++;
        }
    }
};
BigNum operator + (const BigNum& t1, const BigNum& t2) {
    ll jin = 0, he = 0;
    BigNum ans;
    ans.len = 0;
    while(ans.len < t1.len && ans.len < t2.len) {
        he = t1.value[ans.len] + t2.value[ans.len] + jin;
        jin = he/SCALE;
        ans.value[ans.len] = he%SCALE;
        ans.len++;
    }
    while(ans.len < t1.len) {
        he = t1.value[ans.len] + jin;
        jin = he/SCALE;
        ans.value[ans.len] = he%SCALE;
        ans.len++;
    }
    while(ans.len < t2.len) {
        he = t2.value[ans.len] + jin;
        jin = he/SCALE;
        ans.value[ans.len] = he%SCALE;
        ans.len++;
    }
    if(jin != 0) {
        ans.value[ans.len] = jin;
        ans.len++;
    }
    return ans;
}
BigNum operator * (const BigNum& t1, const int& t2) {
    BigNum ans;
    ll jin = 0, t;
    for(int i = 0; i < t1.len; i++) {
        t = t1.value[i]*t2 + jin;
        jin = t/SCALE;
        ans.value[i] = t%SCALE;
    }
    ans.len = t1.len;
    if(jin != 0) {
        ans.value[ans.len] = jin;
        ans.len++;
    }
    return ans;
}
BigNum operator - (const BigNum& t1, const BigNum& t2) {
    BigNum ans;
    ll jie = 0, t;
    for(int i = 0; i < t2.len; i++) {
        t = t2.value[i] + jie;
        if(t > t1.value[i]) {
            jie = 1;
            ans.value[i] = SCALE + t1.value[i] - t;
        }
        else {
            jie = 0;
            ans.value[i] = t1.value[i] - t;
        }
    }
    for(ans.len = t2.len; ans.len < t1.len; ans.len++) {
        if(jie > t1.value[ans.len]) {
            ans.value[ans.len] = SCALE + t1.value[ans.len] - jie;
            jie = 1;
        }
        else {
            ans.value[ans.len] = t1.value[ans.len] - jie;
            jie = 0;
        }
    }
    if(ans.value[ans.len - 1] == 0) ans.len--;
    return ans;
}
void print(BigNum& ans) {
    printf("%d", ans.value[ans.len - 1]);
    for(int i = ans.len - 2; i >= 0; i--) {
        printf("%09d", ans.value[i]);
    }
    puts("");
}

o1快速乘

inline long long multi(long long x,long long y,long long mod)
{
    long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
    return tmp<0 ? tmp+mod : tmp;
}


日后再补充。。。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值