后缀自动机
/** @xigua */ #include <stdio.h> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <cstring> #include <queue> #include <set> #include <string> #include <map> #include <climits> #define PI acos(-1) #define rep(a,b,c) for(int (a)=(b); (a)<(c); ++(a)) #define drep(a,b,c) for(int (a)=(b); (a)>(c); --(a)) #define CLR(x) memset(x, 0, sizeof(x)) #define sf scanf #define pf printf using namespace std; typedef long long ll; typedef double db; const int maxn = 250000 + 1000; const int ma = 1e5 + 1000; const int mod = 1e9 + 7; const int INF = 1e8 + 5; const ll inf = 1e17 + 5; const db eps = 1e-6; const int MAXN = 2e5+1e3; struct SAM{ int ch[maxn<<1][26]; int fa[maxn<<1], len[maxn<<1]; int cnt, last, root; void init() { root=1; memset(ch, 0, sizeof(ch)); memset(fa, 0, sizeof(fa)); last=cnt=root; } void add(int c) { int p=last, np=last=++cnt; len[np]=len[p]+1; while(!ch[p][c] && p) { ch[p][c]=np; p=fa[p]; } if (p==0) fa[np]=1; else { int q = ch[p][c]; if(len[p] + 1 == len[q]) { fa[np] = q; } else { int nq = ++cnt; len[nq] = len[p] + 1; memcpy(ch[nq], ch[q], sizeof ch[q]); fa[nq] = fa[q]; fa[q] = fa[np] = nq; while(ch[p][c] == q && p) { ch[p][c] = nq; p = fa[p]; } } } } int find(char *s) { int p=root, l=0, c=0; int lenn=strlen(s); for(int i = 0; i < lenn; i++) { if(ch[p][s[i] - 'a']) { p = ch[p][s[i] - 'a']; c++; } else { while(p&&!ch[p][s[i]-'a']) p=fa[p]; if (!p) c=0, p=1; else c=len[p]+1, p=ch[p][s[i]-'a']; } l = max(l, c); } printf("%d\n", l); } }sam; char s[maxn]; void solve() { scanf("%s", s); int lenn=strlen(s); sam.init(); for (int i=0; i<lenn; i++) { sam.add(s[i]-'a'); } scanf("%s", s); sam.find(s); } int main() { int t = 1, cas = 1; //freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); //scanf("%d", &t); while(t--) { // printf("Case %d: ", cas++); solve(); } return 0; }
回文树板子【已更改。再乱初始化我吃屎!】注意初始化!!:
/* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<queue> #include<set> #include<string> #include<map> #include <time.h> #define PI acos(-1) using namespace std; typedef long long ll; typedef double db; const int maxn = 1e5+10; const int sigma=26; const ll mod = 1000000007; const int INF = 0x3f3f3f; const db eps = 1e-9; struct ptree{ char s[maxn]; int next[maxn][sigma], fail[maxn], cnt[maxn], len[maxn]; int last, n, p; ll res; inline int newnode(int l) { memset(next[p], 0, sizeof(next[p])); cnt[p]=0; len[p]=l; return p++; } inline void init() { n=0, p=0, last=0; newnode(0), newnode(-1); s[n]=-1; fail[0]=1; } inline int FL(int x) { while(s[n-len[x]-1]!=s[n]) x=fail[x]; return x; } int add(char c) { c-='a'; s[++n]=c; int cur=FL(last); if (!next[cur][c]) { int now=newnode(len[cur]+2); fail[now]=next[FL(fail[cur])][c]; cnt[now]=cnt[fail[now]]+1; next[cur][c]=now; } last=next[cur][c]; return cnt[last]; } }p; char s[maxn]; ll sum[maxn]; void solve(){ while(scanf("%s",s)!=EOF) { int len=strlen(s); p.init(); memset(sum, 0, sizeof(sum)); ll ans=0; for (int i=len-1; i>=0; i--) { sum[i] = sum[i+1]+p.add(s[i]); } p.init(); for (int i=0; i<len; i++) { ans += (ll)p.add(s[i])*sum[i+1]; } printf("%lld\n", ans); } } int main() { int t = 1; freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); //scanf("%d", &t); while(t--) solve(); return 0; }
超强回文树板子:
const int MAXN = 100005, SIZE = 26; struct Palindromic_Tree { int next[MAXN][SIZE];//next指针 int fail[MAXN];//fail指针 int cnt[MAXN];//表示节点i表示的回文串的个数(建树时求出的不是完全的,最后Count()函数跑一遍以后才是正确的) int num[MAXN];//表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数 int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串) int S[MAXN];//存放添加的字符 int last;//指向上一个字符所在的节点,方便下一次add int n;//字符数组指针 int p;//节点指针 int NewNode(int L) {//新建节点 for(int i = 0; i < SIZE; ++i) next[p][i] = 0; cnt[p] = num[p] = 0; len[p] = L; return p++; } void Init() {//初始化 p = n = 0; NewNode(0); NewNode(-1); last = 0; S[n] = -1;//开头放一个字符集中没有的字符,减少特判 fail[0] = 1; } int GetFail(int x) {//和KMP一样,失配后找一个尽量最长的 while(S[n - len[x] - 1] != S[n]) x = fail[x]; return x; } int Add(int c) { S[++n] = c; int cur = GetFail(last);//通过上一个回文串找这个回文串的匹配位置 if(!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 int now = NewNode(len[cur] + 2);//新建节点 fail[now] = next[GetFail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转 next[cur][c] = now; num[now] = num[fail[now]] + 1; } last = next[cur][c]; cnt[last]++; return num[last]; } void Count() { for(int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i]; //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串! } }tree;
凸包极角排序(得到最后形成凸包的点)Graham扫描算法:
#include<stdio.h> #include<math.h> #define eps 1e-10 #define pi 3.1415926535898 #define N 1010 /* point[]:输入的点集 ch[]:输出的凸包上的点集,按照逆时针方向排列 n:point中的点的数目 len:输出的凸包上的点的个数 */ struct node { double x,y; } point[N],ch[N]; int n,len; double multi(node a,node b,node c) { return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x); } double dis(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } void graham_scan(node point[N],node ch[N],int n) { int i,j,k,top; struct node t; k=0; //找到最下且偏左的那个点 for(i=1; i<n; i++) if(point[i].y<point[k].y||(point[i].y==point[k].y&&(point[i].x<point[k].x))) k=i; t=point[0];//将这个点指定为point[0]; point[0]=point[k]; point[k]=t; //按极角从小到大,距离偏短进行排序 for(i=1; i<n-1; i++) { k=i; for(j=i+1; j<n; j++) if(multi(point[j],point[k],point[0])>0||(fabs(multi(point[j],point[k],point[0]))<=eps&& (dis(point[0],point[j])<dis(point[0],point[k])))) k=j; //k保存极角最小的那个点,或者相同距离原点最近 t=point[i]; point[i]=point[k]; point[k]=t; } //第三个点先入栈 ch[0]=point[0]; ch[1]=point[1]; ch[2]=point[2]; top=2; //判断与其余所有点的关系 for(i=3; i<n; i++) { //不满足向左转的关系,栈顶元素出栈 while(multi(point[i],ch[top],ch[top-1])>0||fabs(multi(point[i],ch[top],ch[top-1]))<=eps) top--; //当前点与栈内所有点满足向左关系,因此入栈 ch[++top]=point[i]; } len=top+1; } int main() { int i; while(scanf("%d",&n)!=EOF) { for(i=0; i<n; i++) scanf("%lf%lf",&point[i].x,&point[i].y); graham_scan(point,ch,n); for(i=0; i<len; i++) printf("%lf %lf\n",ch[i].x,ch[i].y); } return 0; }