您的位置:首页 > 其它

ACM算法模板

2016-07-28 23:53 344 查看
1.头文件

#define _CRT_SBCURE_MO_DEPRECATE  
#include<iostream>  
#include<stdlib.h>  
#include<stdio.h>  
#include<cmath>  
#include<algorithm>  
#include<string>  
#include<string.h>  
#include<set>  
#include<queue>  
#include<stack>  
#include<functional>   
using namespace std;
const int maxn = 100 + 10;
const int INF = 0x3f3f3f3f;<span id="transmark" style="display: none; width: 0px; height: 0px;"></span>


2.筛选法求素数

伪代码
IS_PRIME(A)

for each i less than A.length + 1

A[i] = 0
for i = 2 to A.length + 1

if A[i] = 0

for all multiples j of i,less than upper bound

A[j] <- 1

代码

for (int i = 2; i < n; i++) {
if (a[i] == 0) {
for (int j = i + 1; j <= 10000; j = j + i) {
a[j] = 1;
}
}
}


3.快速幂

快速幂公式:
typedef long long LL;//视情况定类型
LL fun(LL x, LL n) {
LL res = 1;
while (n > 0) {
if (n & 1)//&按位与判奇偶  4>>1 = 4/2  2<<1 = 2*2
res = (res*x);//求幂,所以无取模
x = x*x;
n >>= 1;
}
return res;
}

快速幂取模

int fun(int a, int b, int n) {
int t = 1, y = a;
while (b != 0){
y %= n;
if (b % 2 == 1)
t = t%n*y%n;
y = y*y%n;
b = b >> 1;
}
return t;
}

4.模拟大数相加

<pre name="code" class="cpp">string add(string s1, string s2) {
if (s1 == ""&&s2 == "") return "0";
if (s1 == "")  return s2;
if (s2 == "")  return s1;
string max = s1, min = s2;
if (s1.length() < s2.length()) {
max = s2;
min = s1;
}
int a = max.length() - 1;
int b = min.length() - 1;
for (int i = b; i >= 0; i--) {
max[a--] += min[i] - '0';//a一直在减
}
for (int i = max.length(); i > 0; i--) {
if (max[i] > '9') {
max[i] = max[i] - 10;
max[i - 1]++;
}
}
if (max[0] > '9') {
max[0] -= 10;
max = '1' + max;
}
return max;
}


模拟大数阶乘:

int main()
{
int large_num[16326] = { 1 };
int num, zero = 0;
int i, j, k, n;
int top;

scanf("%d", &num);
for (i = 2, top = 1; i <= num; i++){
k = i;
while (k % 10 == 0){
k /= 10;
zero++;
}
for (j = 0; j < top; j++)
large_num[j] *= k;

for (n = 0; ; n++){
large_num[n + 1] += large_num
/ 10;
large_num
%= 10;
if (n + 1 == top){
if (large_num[n + 1] != 0)
top++;
else
break;
}
}
}
for (i = top - 1; i >= 0; i--)
printf("%d", large_num[i]);
for (i = 0; i < zero; i++)
printf("0");
printf("\n");
return 0;
}


5.最大公约数

公约数求公倍数:乘积/最大公约数
int gad(int da, int xiao) {
int temp;
while (xiao!=0) {
temp = da%xiao;
da = xiao;
xiao = temp;
}
return (da);
}


6.全排列
求1-n的全排列

void Perm(int list[], int k, int m) {
if (k == m - 1) {
for (int i = 0; i < m; i++) {
printf("%d", list[i]);
}
printf("\n");
}
else {
for (int i = k; i < m; i++) {
swap(list[k], list[i]);
Perm(list, k + 1, m);
swap(list[k], list[i]);
}
}
}


7.二分搜索
int bsearch(int *A, int x, int y, int v) {
x为最开始元素 y是末尾元素的下一个数 v是要找的数

int m;
while (x < y) {

m = x + (y - x) / 2;

if (A[m] >= v) y = m;  //如果要替换为 upper_bound, 改为:if(A[m] <= v) x = m+1;  else y = m;

else x = m + 1;

}

return x;

}
//最后x == y
//
如果没有找到 135577找6,返回7
//
如果找有多少的v,可以用lower_bound查找一遍,upper_bound查找一遍,下标相减
//

lower_bound(a,a+n,v)返回数组中最后一个v的下一个数的地址

//upper_bound(a,a+n,v)返回数组中第一个v的地址
//如果a+n内没有找到v或v的下一个地址,返回a+n的地址

//lower_bound(a, a + n, v)-upper_bound(a, a + n, v)返回数组中v的个数


8.背包问题
01背包:

void bag01(int cost,int weight)
{
for(i=v;i>=cost;i--)
dp[i] = max(dp[i], dp[i-cost]+weight);
}

完全背包:

void complete(int cost,int weight)
{
for(i=cost;i<=v;i++)
dp[i] = max(dp[i], dp[i-cost]+weight);
}

多重背包:

void multiply(int cost,int weight,int amount)
{
if(cost*amount>=v)
complete(cost,weight);
else{
k=1;
while(k<amount){
bag01(k*cost,k*weight);
amount-=k;
k+=k;
}
bag01(cost*amount,weight*amount);
}
}


9.LIS最长上升子序列

状态转移dp[i] = max{ 1.dp[j] + 1 }; j<i;a[j]<a[i];
d[i]是以i结尾的最长上升子序列
与i之前的 每个a[j]<a[i]的 j的位置的 最长上升子序列+1后 的值比较

void solve(){   // 参考挑战程序设计入门经典;

for(int i = 0; i < n; ++i){

dp[i] = 1;

for(int j = 0; j < i; ++j){

if(a[j] < a[i]){

dp[i] = max(dp[i], dp[j]+1);

}

}

}

}

优化方法
//dp[i]表示长度为i+1的上升子序列的最末尾元素;
//找到第一个比dp末尾大的,代替
void solve() {
fill(dp, dp + n, INF);
for (int i = 0; i < n; i++) {
*lower_bound(dp, dp + n, a[i]) = a[i];//返回一个指针
}
printf("%d\n", *lower_bound(dp, dp + n, INF) - dp;
}
//函数lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,而不会破坏容器顺序的第一个位置,而这个位置标记了一个不小于value 的值。


10.最长公共子序列
求最长公共子序列 递推
void solve() {

for (int i = 0; i < n; ++i) {

for (int j = 0; j < m; ++j) {

if (s1[i] == s2[j]) {

dp[i + 1][j + 1] = dp[i][j] + 1;

}

else {

dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);

}
}

}
}

11.并查集

int father[100];//储存i的father父节点

void makeSet() {
for (int i = 0; i < 100; i++)
father[i] = i;
}

int findRoot(int x) { //递归查找根节点
if (father[x] == x)
return x;
else
return findRoot(father[x]);
}

int Find(int x) { // 路径压缩 递推 优化:关键在于在路径上的每个节点都可以直接连接到根上
if (father[x] != x) father[x] = Find(father[x]);
return father[x];
}
int DFind(int x) {//路径压缩 迭代 最优版
int root = x; //根节点
while (root != father[root]) { //寻找根节点
root = father[root];
}
while (x != root) {
int tmp = father[x];
father[x] = root; //根节点赋值
x = tmp;
}
return root;
}

void Union(int x, int y) {//将x所在的集合和y所在的集合整合起来形成一个集合。
int a, b;
a = findRoot(x);
b = findRoot(y);
father[a] = b;  //y连在x的根节点上   或father[b] = a为x连在y的根节点上;
}

12.并查集的MST——.Kruskal算法 (稀疏图)

第一步:点、边、加入vector,把所有边按从小到大排序

第二步:下面代码

void Kruskal() {
ans = 0;
for (int i = 0; i<len; i++) {
if (Find(edge[i].a) != Find(edge[i].b)) {
Union(edge[i].a, edge[i].b);
ans += edge[i].len;
}
}
}

13.并查集的MST——Prim算法 (稠密图)

时间复杂度:O(n方)

void Init()
{
for (int i = 0; i < maxn; ++i) {
G[i].clear();
intree[i] = false;
mindist[i] = INF;//初始化为最大值,因为开始的时候F为空,到V的任意节点都不连通,用INF表示
}
}
int Prim(int s)//s是第一个加入生成树的结点
{
int ans = 0;
int vex, addNode, tempMin;//加入集合F中的节点

intree[s] = true;//加入生成树
for (unsigned int i = 0; i < G[s].size(); ++i) {//更新mindistG[s][i].vex即所有与s连通的节点vex
vex = G[s][i].vex;
mindist[vex] = G[s][i].weight;
}
for (int nodeNum = 1; nodeNum <= n - 1; ++nodeNum) {//对于集合V中剩余的n-1个节点
tempMin = INF;
for (int i = 1; i <= n; ++i) {//从集合V中找出到F最小距离的边,
if (intree[i] == false && mindist[i] < tempMin) {
tempMin = mindist[i];
addNode = i;
}
}
intree[addNode] = true;//addNode 加入集合F
ans += tempMin;//此时tempMin是最小权值
for (unsigned int i = 0; i < G[addNode].size(); ++i) {//addNode加入集合F后更新F到V的最小距离,这里最关键!
vex = G[addNode][i].vex;
if (intree[vex] == false && G[addNode][i].weight < mindist[vex])
mindist[vex] = G[addNode][i].weight;
}
}
return ans;
}

Prim算法优化版,用堆

时间复杂度:O(elgn)

struct node {
int v, len;
node(int v = 0, int len = 0) :v(v), len(len) {}
bool operator < (const node &a)const {  //加入队列的元素自动按距离从小到大排序
return len> a.len;
}
};
void init() {
for (int i = 0; i<maxn; i++) {
G[i].clear();
dis[i] = INF;
vis[i] = false;
}
}
void Prim(int s) {
priority_queue<node>Q;//定义优先队列
int ans = 0;
Q.push(node(s,0)); //起点加入队列
while (!Q.empty()) {
node now = Q.top(); Q.pop(); //取出距离最小的点
int v = now.v;
if (vis[v]) continue; //同一个节点,可能会推入2次或2次以上队列,这样第一个被标记后,剩下的需要直接跳过。
vis[v] = true; //标记一下
ans += now.len;
for (int i = 0; i<G[v].size(); i++) { //开始更新
int v2 = G[v][i].v;
int len = G[v][i].len;
if (!vis[v2] && dis[v2] > len) {
dis[v2] = len;
Q.push(node(v2, dis[v2])); //更新的点加入队列并排序
}
}
}
printf("%d\n", ans);
}


14.单源最短路算法——Dijkstra

适用于边权为正、求从单个源点出发,到所有节点的最短路  有向图或者无向图

void init()
{
for (int i = 0; i < maxn; i++) {
intree[i] = false;
G[i].clear();
mindist[i] = INF;
}
}

int Perim(int s, int t) {
int ans = 0;
int vex, addNode, tempMin;
intree[s] = true;
mindist[s] = 0;
for (int i = 0; i < G[s].size(); i++) {//找开始点周围的路径并初始化
vex = G[s][i].vex;
mindist[vex] = Min(mindist[vex], G[s][i].weight);
}
for (int nodeNum = 1; nodeNum <= n - 1; nodeNum++) {//向周围n-1个点找
tempMin = INF;
for (int i = 0; i < n; i++) {
if (intree[i] == false && mindist[i] < tempMin) {//寻找最短路径
tempMin = mindist[i];
addNode = i;
}
}
intree[addNode] = true;
for (int i = 0; i < G[addNode].size(); i++) {//更新
vex = G[addNode][i].vex;
if (intree[vex] == false && mindist[addNode] + G[addNode][i].weight < mindist[vex])
mindist[vex] = mindist[addNode] + G[addNode][i].weight;
}
}
return mindist[t];
}


二维数组+路径打印:

#include<stdio.h>
#include<string.h>
#define INF 100000000
#define maxn 1001
bool vis[maxn];
int adj[maxn][maxn],dis[maxn],pre[maxn];//pre[]记录前驱
int n, m;
void dijkstra(int v)
{
int i, j, u , min;
for(i=0;i<=n;i++)
{
dis[i]=adj[v][i];
vis[i]=0;
//if(i!=v&&adj[v][i]!=INF)pre[i] = v;
// else pre[i] = -1;
}
vis[v]=1;dis[v]=0;
for(i=1;i<n;i++)
{
min = INF;
for(j=1;j<=n;j++)
{
if(!vis[j]&&min > dis[j])
{
min = dis[j];
u = j;
}
}
if(min == INF)break;
vis[u]=1;
for(j=1;j<=n;j++)
{
if(!vis[j]&&adj[u][j]!=INF&&dis[u]+adj[u][j]<dis[j])
{
dis[j] = adj[u][j] + dis[u];
//  pre[j] = u;
}
}
}
}
int main()
{
int i, j, x, y, w;
while(~scanf("%d%d",&n,&m)&&n)
{
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
if(i==j)adj[i][j]=0;
else adj[i][j] = INF;
}
while(m--)
{
scanf("%d%d%d",&x,&y,&w);
adj[x][y] = w;
adj[y][x] = w;
}
dijkstra(0);
printf("%d\n",dis
);  //以下为输出路径
/*int p, len=0, ans[maxn];
p = n-1;
while(p!=0)
{
ans[len++] = p;
p = pre[p];

}
printf("0->");
for(i=len-1;i>=0;i--)
printf("%d",ans[i]);
puts("");  */
}
return 0;
}


优化版:时间复杂度 O(elbn)

struct node {
int v, len;
node(int v = 0, int len = 0) :v(v), len(len) {}
bool operator < (const node &a)const { //距离从小到大排序
return len > a.len;
}
};
vector<node>G[maxn];
bool vis[maxn];
int dis[maxn];
void init() {
for (int i = 0; i<maxn; i++) {
G[i].clear();
vis[i] = false;
dis[i] = INF;
}
}
int dijkstra_heap(int s, int e) {
priority_queue<node>Q;
Q.push(node(s, 0));//加入队列并排序
dis[s] = 0;
while (!Q.empty()) {
node now = Q.top(); //取出当前最小的
Q.pop();
int v = now.v;
if (vis[v]) continue; //如果标记过了 直接continue
vis[v] = true;
for (int i = 0; i<G[v].size(); i++) { //更新
int v2 = G[v][i].v;
int len = G[v][i].len;
if (!vis[v2] && dis[v2] > dis[v] + len) {
dis[v2] = dis[v] + len;
Q.push(node(v2, dis[v2]));
}
}
}
return dis[e];
}


15.Bellman-Ford算法的一种队列优化---SPFA 算法

时间复杂度减少,而且也可以处理负环的情况

//不断的将s的邻接点加入队列,取出不断的进行松弛操作,直到队列为空
//如果一个结点被加入队列超过n-1次,那么显然图中有负环
void Init()
{
for(int i = 0 ; i < maxn ; ++i){
G[i].clear();
dist[i] = INF;
}
}
int SPFA(int s,int e)
{
int v1,v2,weight;
queue<int> Q;
memset(inqueue,false,sizeof(inqueue));//标记是否在队列中
memset(cnt,0,sizeof(cnt));//加入队列的次数
dist[s] = 0;
Q.push(s);//起点加入队列
inqueue[s] = true;//标记
while(!Q.empty()){
v1 = Q.front();
Q.pop();
inqueue[v1] = false;//取消标记
for(int i = 0 ; i < G[v1].size() ; ++i){//搜索v1的链表
v2 = G[v1][i].vex;
weight = G[v1][i].weight;
if(dist[v2] > dist[v1] + weight){ //松弛操作
dist[v2] = dist[v1] + weight;
if(inqueue[v2] == false){ //再次加入队列
inqueue[v2] = true;
//cnt[v2]++; 判负环
//if(cnt[v2] > n) return -1;
Q.push(v2);
}
}
}
}
return dist[e];
}

16.Floyd-Warshall算法——任意点对最短路算法

求图中任意两点的最短距离的算法

for (int i = 0; i < n; i++) {//初始化为0
for (int j = 0; j < n; j++)
scanf("%lf", &dis[i][j]);
}
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}

17.染色法判断二分图

int bipartite(int s) {
int u, v;
queue<int>Q;
color[s] = 1;
Q.push(s);
while (!Q.empty()) {
u = Q.front();
Q.pop();
for (int i = 0; i < G[u].size(); i++) {
v = G[u][i];
if (color[v] == 0) {
color[v] = -color[u];
Q.push(v);
}
else if (color[v] == color[u])
return 0;
}
}
return 1;
}

18.匈牙利算法 求解最大匹配问题

递归 腾

vector<int>G[maxn];
bool inpath[maxn];//标记
int match[maxn];//记录匹配对象
void init()
{
memset(match, -1, sizeof(match));
for (int i = 0; i < maxn; i++) {
G[i].clear();
}
}
bool findpath(int k) {
for (int i = 0; i < G[k].size(); i++) {
int v = G[k][i];
if (!inpath[v]) {
inpath[v] = true;
if (match[v] == -1 || findpath(match[v])) {//递归
match[v] = k;//即匹配对象是“k妹子”的
return true;
}
}
}
return false;
}

void hungary() {
int cnt = 0;
for (int i = 1; i <= m; i++) { //m为需要匹配的“妹子”数
memset(inpath, false, sizeof(inpath));//每次都要初始化
if (findpath(i)) cnt++;
}
cout << cnt << endl;
}

dfs版:

int v1, v2;
bool Map[501][501];
bool visit[501];
int link[501];

int result;
bool dfs(int x)
{
for (int y = 1; y <= v2; y++)
{
if (Map[x][y] && !visit[y])
{
visit[y] = true;
if (link[y] == 0 || dfs(link[y]))
{
link[y] = x;
return true;
}
}
}
return false;
}

void Search()
{
for (int x = 1; x <= v1; x++)
{
memset(visit,false,sizeof(visit));
if (dfs(x))
result++;
}
}
<pre><span style="color:#000000;">memset(Map,</span><span style="color:#800080;">0</span>,<span style="color:#0000ff;">sizeof</span><span style="color:#000000;">(Map));</span>




19.求多边形面积

struct node {
double x;//横坐标
double y;//纵坐标
};

node G[maxn];
int n;

double Cross(node a, node b) { //叉积计算
return a.x*b.y - a.y*b.x;
}

int main()
{
while (scanf("%d", &n) != EOF && n) {
for (int i = 0; i < n; i++)
scanf("%lf %lf", &G[i].x, &G[i].y);
double sum = 0;
G
.x = G[0].x;
G
.y = G[0].y;
for (int i = 0; i < n; i++) {
sum += Cross(G[i], G[i + 1]);
}
//或者
//for (int i = 0; i < n; i++) {
//sum += fun(G[i], G[(i + 1)% n]);
//}
sum = sum / 2.0;
printf("%.1f\n", sum);
}
system("pause");
return 0;
}


20.向量基本用法
Vector operator + (Vector A, Vector B) { return Vector(A.x + B.x, A.y + B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x - B.y, A.y - B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x / p, A.y*p); }

double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }//向量点乘
double Length(Vector A) { return sqrt(Dot(A, A)); } //向量模长
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } //向量之间夹角

double Cross(Vector A, Vector B) { //叉积计算 公式
return A.x*B.y - A.y*B.x;
}

Vector Rotate(Vector A, double rad)//向量旋转 公式
{
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
}

Point getLineIntersection(Point P, Vector v, Point Q, Vector w)//两直线交点t1 t2计算  公式
{
Vector u = P - Q;
double t = Cross(w, u) / Cross(v, w);  //求得是横坐标
return P + v*t;  //返回一个点
}

21.判断线段相交

struct node
{
double x,y;
};
node P[35][105];
double Cross_Prouct(node A,node B,node C)       //  计算BA叉乘CA;
{
return (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x);
}
bool Intersect(node A,node B,node C,node D)     //  通过叉乘判断线段是否相交;
{
if(min(A.x,B.x)<=max(C.x,D.x)&&         //  快速排斥实验;
min(C.x,D.x)<=max(A.x,B.x)&&
min(A.y,B.y)<=max(C.y,D.y)&&
min(C.y,D.y)<=max(A.y,B.y)&&
Cross_Prouct(A,B,C)*Cross_Prouct(A,B,D)<0&&      //  跨立实验;
Cross_Prouct(C,D,A)*Cross_Prouct(C,D,B)<0)       //  叉乘异号表示在两侧;
return true;
else return false;
}

22.求三角形外心

Point circumcenter(const Point &a, const Point &b, const Point &c)//返回三角形的外心
{
Point ret;
double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1) / 2;
double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2) / 2;
double d = a1*b2 - a2*b1;
ret.x = a.x + (c1*b2 - c2*b1) / d;
ret.y = a.y + (a1*c2 - a2*c1) / d;
return ret;
}


23.极角排序

double cross(point p1, point p2, point q1, point q2)//叉积计算
{
return (q2.y - q1.y)*(p2.x - p1.x) - (q2.x - q1.x)*(p2.y - p1.y);
}
bool cmp(point a, point b)
{
point o;
o.x = o.y = 0;
return cross(o, b, o, a) < 0; //叉积判断
}
sort(convex + 1, convex + cnt, cmp);//按角排序 从小到大

24.kmp算法

void getnext(int b[maxn], int next[maxm]) {
int j = 0, k = -1;
next[0] = -1;
while (j < m - 1) {//m是字符串长度
if (k == -1 || b[j] == b[k]) {
j++;
k++;
next[j] = k;
}
else
k = next[k];
}
}

void kmp(int a[maxn], int b[maxn]) {
int next[maxm];
int i = 0, j = 0;
getnext(b, next);
while (i < n) {
if (j == -1 || a[i] == b[j]) {//母串不动,子串移动
j++;
i++;
}
else {
// i不需要回溯了
// i = i - j + 1;
j = next[j];
}
if (j == m) {
printf("%d\n", i - m + 1);//母串的位置减去子串的长度+1
return;
}
}
printf("-1\n");
}


kmp扩展

#include<iostream>
#include<cstring>
using namespace std;
const int MM=100005;

int next[MM],extand[MM];

char S[MM],T[MM];

void GetNext(const char *T) {
int len = strlen(T),a = 0;

next[0] = len;

while(a < len - 1 && T[a] == T[a + 1]) a++;

next[1] = a;
a = 1;

for(int k = 2; k < len; k ++) {

int p = a + next[a] - 1,L = next[k - a];

if( (k - 1) + L >= p) {

int j = (p - k + 1) > 0 ? (p - k + 1) : 0;

while(k + j < len && T[k + j] == T[j]) j++;

next[k] = j;

a = k;

} else
next[k] = L;
}
}

void GetExtand(const char *S,const char *T) {
GetNext(T);

int slen = strlen(S),tlen = strlen(T),a = 0;

int MinLen = slen < tlen ? slen : tlen;

while(a < MinLen && S[a] == T[a]) a++;

extand[0] = a;

a = 0;

for(int k = 1; k < slen; k ++) {

int p = a + extand[a] - 1, L = next[k - a];

if( (k - 1) + L >= p) {

int j = (p - k + 1) > 0 ? (p - k + 1) : 0;

while(k + j < slen && j < tlen && S[k + j] == T[j]) j ++;

extand[k] = j;

a = k;

} else
extand[k] = L;
}
}
void show(const int *s,int len){

for(int i = 0; i < len; i ++)
cout << s[i] << ' ';
cout << endl;
}

int main() {
while(cin >> S >> T) {
GetExtand(S,T);
show(next,strlen(T));
show(extand,strlen(S));
}
return 0;
}


25.字典树

struct Trie{
int cnt;
Trie *next[maxn];
Trie(){
cnt = 0;
memset(next,0,sizeof(next));
}
};

Trie *root;

void Insert(char *word)
{
Trie *tem = root;
while(*word != '\0')
{
int x = *word - 'a';
if(tem->next[x] == NULL)
tem->next[x] = new Trie;
tem = tem->next[x];
tem->cnt++;
word++;
}
}

int Search(char *word)
{
Trie *tem = root;
for(int i=0;word[i]!='\0';i++)
{
int x = word[i]-'a';
if(tem->next[x] == NULL)
return 0;
tem = tem->next[x];
}
return tem->cnt;
}

void Delete(char *word,int t)
{
Trie *tem = root;
for(int i=0;word[i]!='\0';i++)
{
int x = word[i]-'a';
tem = tem->next[x];
(tem->cnt)-=t;
}
for(int i=0;i<maxn;i++)
tem->next[i] = NULL;
}

int main()
{
int n;
char str1[50];
char str2[50];
while(scanf("%d",&n)!=EOF)
{
root = new Trie;
while(n--)
{
scanf("%s %s",str1,str2);
if(str1[0]=='i')
Insert(str2);
else if(str1[0] == 's')
{
if(Search(str2))
printf("Yes\n");
else
printf("No\n");
}
else
{
int t = Search(str2);
if(t)
Delete(str2,t);
}
}
}
return 0;
}


26.AC自动机

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>

using namespace std;

#define N 1000010

char str
, keyword
;
int head, tail;

struct node
{
node *fail;
node *next[26];
int count;
node() //init
{
fail = NULL;//默认为空
count = 0;
for(int i = 0; i < 26; ++i)
next[i] = NULL;
}
}*q
;

node *root;

void insert(char *str) //建立Trie
{
int temp, len;
node *p = root;
len = strlen(str);
for(int i = 0; i < len; ++i)
{
temp = str[i] - 'a';
if(p->next[temp] == NULL)
p->next[temp] = new node();
p = p->next[temp];
}
p->count++;
}

void build_ac() //初始化fail指针,BFS 数组模拟队列:
{
q[tail++] = root;
while(head != tail)
{
node *p = q[head++]; //弹出队头
node *temp = NULL;
for(int i = 0; i < 26; ++i)
{
if(p->next[i] != NULL)
{
if(p == root) //第一个元素fail必指向根
p->next[i]->fail = root;
else
{
temp = p->fail; //失败指针
while(temp != NULL) //2种情况结束:匹配为空or找到匹配
{
if(temp->next[i] != NULL) //找到匹配
{
p->next[i]->fail = temp->next[i];
break;
}
temp = temp->fail;
}
if(temp == NULL) //为空则从头匹配
p->next[i]->fail = root;
}
q[tail++] = p->next[i]; //入队
}
}
}
}

int query() //扫描
{
int index, len, result;
node *p = root; //Tire入口
result = 0;
len = strlen(str);
for(int i = 0; i < len; ++i)
{
index = str[i] - 'a';
while(p->next[index] == NULL && p != root) //跳转失败指针
p = p->fail;
p = p->next[index];
if(p == NULL)
p = root;
node *temp = p; //p不动,temp计算后缀串
while(temp != root && temp->count != -1)
{
result += temp->count;
temp->count = -1;
temp = temp->fail;
}
}
return result;
}

int main()
{
int num;
head= tail = 0;
root = new node();
scanf("%d", &num);
getchar();
for(int i = 0; i < num; ++i)
{
scanf("%s",keyword);
insert(keyword);
}
build_ac();
scanf("%s", str);
if(query())
printf("YES\n");
else
printf("NO\n");
return 0;
}


27.线段树

点更新

struct node{
int l,r,maxn,sum;
}tree[N<<2];

void build(int m,int l,int r){
tree[m].l = l;
tree[m].r = r;
if(l == r){
tree[m].maxn = a[l];
tree[m].sum = a[l];
return ;
}
int mid = (l+r)>>1;
build(m<<1,l,mid);
build((m<<1)+1,mid+1,r);
tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn);
tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum;
}

void update(int m,int a,int val){
if(tree[m].l == a && tree[m].r == a){
tree[m].maxn = val;
tree[m].sum = val;
return ;
}
int mid = (tree[m].l+tree[m].r)>>1;
if(a <= mid)
update(m<<1,a,val);
else
update((m<<1)+1,a,val);
tree[m].maxn = max(tree[m<<1].maxn,tree[(m<<1)+1].maxn);
tree[m].sum = tree[m<<1].sum + tree[(m<<1)+1].sum;
}

int query_max(int m,int l,int r){
if(l == tree[m].l && r == tree[m].r)
return tree[m].maxn;
//return tree[m].sum;
int mid = (tree[m].l+tree[m].r)>>1;
if(r <= mid)
return query_max(m<<1,l,r);
if(l > mid)
return query_max((m<<1)+1,l,r);
return max(query_max(m<<1,l,mid), query_max((m<<1)+1,mid+1,r));
//return query_sum(m<<1,l,mid) + query_sum((m<<1)+1,mid+1,r);
}

build(1,1,n);
update(1,a,b);
query(1,a,b);


区间更新

typedef long long ll;
const int maxn = 100010;

int t,n,q;
ll anssum;

struct node{
ll l,r;
ll addv,sum;
}tree[maxn<<2];

void maintain(int id)
{
if(tree[id].l >= tree[id].r)
return ;
tree[id].sum = tree[id<<1].sum + tree[id<<1|1].sum;
}

void pushdown(int id)
{
if(tree[id].l >= tree[id].r)
return ;
if(tree[id].addv){
int tmp = tree[id].addv;
tree[id<<1].addv += tmp;
tree[id<<1|1].addv += tmp;
tree[id<<1].sum += (tree[id<<1].r - tree[id<<1].l + 1)*tmp;
tree[id<<1|1].sum += (tree[id<<1|1].r - tree[id<<1|1].l + 1)*tmp;
tree[id].addv = 0;
}
}

void build(int id,ll l,ll r)
{
tree[id].l = l;
tree[id].r = r;
tree[id].addv = 0;
tree[id].sum = 0;
if(l==r)
{
tree[id].sum = 0;
return ;
}
ll mid = (l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
maintain(id);
}

void updateAdd(int id,ll l,ll r,ll val)
{
if(tree[id].l >= l && tree[id].r <= r)
{
tree[id].addv += val;
tree[id].sum += (tree[id].r - tree[id].l+1)*val;
return ;
}
pushdown(id);
ll mid = (tree[id].l+tree[id].r)>>1;
if(l <= mid)
updateAdd(id<<1,l,r,val);
if(mid < r)
updateAdd(id<<1|1,l,r,val);
maintain(id);
}

void query(int id,ll l,ll r)
{
if(tree[id].l >= l && tree[id].r <= r){
anssum += tree[id].sum;
return ;
}
pushdown(id);
ll mid = (tree[id].l + tree[id].r)>>1;
if(l <= mid)
query(id<<1,l,r);
if(mid < r)
query(id<<1|1,l,r);
maintain(id);
}

int main()
{
scanf("%d",&t);
int kase = 0 ;
while(t--){
scanf("%d %d",&n,&q);
build(1,1,n);
int id;
ll x,y;
ll val;
printf("Case %d:\n",++kase);
while(q--){
scanf("%d",&id);
if(id==0){
scanf("%lld %lld %lld",&x,&y,&val);
updateAdd(1,x+1,y+1,val);
}
else{
scanf("%lld %lld",&x,&y);
anssum = 0;
query(1,x+1,y+1);
printf("%lld\n",anssum);
}
}
}
return 0;
}

28.中国剩余定理

int CRT(int a[],int m[],int n)
{
int M = 1;
int ans = 0;
for(int i=1; i<=n; i++)
M *= m[i];
for(int i=1; i<=n; i++)
{
int x, y;
int Mi = M / m[i];
extend_Euclid(Mi, m[i], x, y);
ans = (ans + Mi * x * a[i]) % M;
}
if(ans < 0) ans += M;
return ans;
}
void extend_Euclid(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    extend_Euclid(b, a % b, x, y);
    int tmp = x;
    x = y;
    y = tmp - (a / b) * y;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm 模板