后缀数组,倍增求sa与求height数组模板 UOJ模板题
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 100010 using namespace std; int sa[maxn],rk[maxn],height[maxn],tmp[maxn],n,k; char s[maxn]; bool cmp_sa(int i,int j) { if (rk[i]!=rk[j]) return rk[i]<rk[j]; int ri=(i+k<n)?rk[i+k]:-1; int rj=(j+k<n)?rk[j+k]:-1; return ri<rj; } void get_sa() { int i; for (i=0;i<=n;i++) { sa[i]=i; rk[i]=s[i]; } for (k=1;k<=n;k<<=1) { sort(sa,sa+n,cmp_sa); tmp[sa[0]]=0; for (i=0;i<n;i++) tmp[sa[i+1]]=tmp[sa[i]]+(cmp_sa(sa[i],sa[i+1])?1:0); for (i=0;i<n;i++) rk[i]=tmp[i]; } } void get_height() { int i,j,k=0; for (i=0;i<n;i++) { if (k) k--; if (rk[i]>=1) j=sa[rk[i]-1]; while (s[i+k]==s[j+k] && i+k<n && j+k<n) k++; height[rk[i]]=k; } } int main() { int i; scanf("%s",s); n=strlen(s); get_sa(); get_height(); for (i=0;i<n;i++) printf("%d ",sa[i]+1); printf(" "); for (i=1;i<n;i++) printf("%d ",height[i]); return 0; }
2-SAT HDU-3062模板题
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define maxn 2005 #define maxm 1000005 using namespace std; stack<int>st; int num,last[maxn],dfn[maxn],low[maxn],vis[maxn],cnt; int col[maxn],color; struct edge { int to,nxt; }e[maxm<<1]; void clear() { num=0;color=0;cnt=0; memset(last,-1,sizeof(last)); memset(dfn,0,sizeof(dfn)); } void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void tarjan(int x) { int i,y,tp; dfn[x]=low[x]=++cnt; st.push(x); vis[x]=1; for (i=last[x];i!=-1;i=e[i].nxt) { y=e[i].to; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if (vis[y]) { low[x]=min(low[x],dfn[y]); } } if (low[x]==dfn[x]) { color++; while (!st.empty()) { tp=st.top(); col[tp]=color; vis[tp]=0; st.pop(); if (tp==x) break; } } } int main() { int i,n,m,x,y,xid,yid,flag; while (scanf("%d%d",&n,&m)!=EOF) { clear(); for(i=1;i<=m;i++) { scanf("%d%d%d%d",&xid,&yid,&x,&y); x=x+(xid<<1); y=y+(yid<<1); add(x,y^1); add(y,x^1); } for(i=0;i<(n<<1);i++) if(!dfn[i]) tarjan(i); flag=0; for (i=0;i<n;i++) if (col[(i<<1)^1]==col[i<<1]) { flag=1; break; } if (flag) printf("NO "); else printf("YES "); } return 0; }
2-SAT UVA1391模板题,注意用tarjan求解2-SAT时,col数组记录了拓扑排序的顺序
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define maxn 400010 #define maxm 400010 using namespace std; stack<int>st; int num,last[maxn],dfn[maxn],low[maxn],vis[maxn],cnt; int col[maxn],color,a[maxn]; struct edge { int to,nxt; }e[maxm]; void clear() { num=0;color=0;cnt=0; memset(last,-1,sizeof(last)); memset(dfn,0,sizeof(dfn)); memset(col,0,sizeof(col)); } void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void tarjan(int x) { int i,y,tp; dfn[x]=low[x]=++cnt; st.push(x); vis[x]=1; for (i=last[x];i!=-1;i=e[i].nxt) { y=e[i].to; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if (vis[y]) { low[x]=min(low[x],dfn[y]); } } if (low[x]==dfn[x]) { color++; while (!st.empty()) { tp=st.top(); col[tp]=color; vis[tp]=0; st.pop(); if (tp==x) break; } } } int main() { int i,n,m,x,y,fx,fy,flag; double sum; while (scanf("%d%d",&n,&m)!=EOF) { if (n==0 && m==0) break; clear(); sum=0; for (i=0;i<n;i++) { scanf("%d",&a[i]); sum+=a[i]; } sum=sum/n; for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); x--;y--; fx=(a[x]<=sum); fy=(a[y]<=sum); if (fx==fy) { add((x<<1),(y<<1)|1); add((y<<1)|1,(x<<1)); add((y<<1),(x<<1)|1); add((x<<1)|1,(y<<1)); } else { add(x<<1|1,y<<1); add(y<<1|1,x<<1); } } for(i=0;i<(n<<1);i++) if(!dfn[i]) tarjan(i); flag=0; for(i=0;i<n;i++) { if (col[(i<<1)|1]==col[i<<1]) { flag=1; break; } } if (flag) printf("No solution. "); else { for(i=0;i<n;i++) { if (col[(i<<1)|1]<col[i<<1]) printf("C "); else { if (a[i]>=sum) printf("A "); else printf("B "); } } } } return 0; }
A POJ 3207
对于交错的连线[xi,yi]与[xj,yj],i在外则j在里,i在里则j在外,反过来也一样。
按照这点做2-SAT就可以了,(然而我没看懂题目),算是模板题。
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define maxn 2005 #define maxm 1000005 using namespace std; stack<int>st; int num,last[maxn],dfn[maxn],low[maxn],vis[maxn],cnt; int x[maxn],y[maxn],col[maxn],color; struct edge { int to,nxt; }e[maxm]; void clear() { num=0;color=0;cnt=0; memset(last,-1,sizeof(last)); memset(dfn,0,sizeof(dfn)); } void add(int x,int y) { e[++num].to=y; e[num].nxt=last[x]; last[x]=num; } void tarjan(int x) { int i,y,tp; dfn[x]=low[x]=++cnt; st.push(x); vis[x]=1; for (i=last[x];i!=-1;i=e[i].nxt) { y=e[i].to; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); } else if (vis[y]) { low[x]=min(low[x],dfn[y]); } } if (low[x]==dfn[x]) { color++; while (!st.empty()) { tp=st.top(); col[tp]=color; vis[tp]=0; st.pop(); if (tp==x) break; } } } int main() { int i,j,n,m,flag; while (scanf("%d%d",&n,&m)!=EOF) { clear(); for(i=1;i<=m;i++) { scanf("%d%d",&x[i],&y[i]); if (x[i]>y[i]) swap(x[i],y[i]); } for (i=1;i<=m;i++) for (j=i+1;j<=m;j++) if ((x[i]<=x[j] && x[j]<=y[i] && y[i]<=y[j]) || (x[i]>=x[j] && x[j]>=y[i] && y[i]>=y[j])) { add((i<<1),(j<<1)|1); add((i<<1)|1,(j<<1)); add((j<<1),(i<<1)|1); add((j<<1)|1,(i<<1)); } for(i=0;i<(n<<1);i++) if(!dfn[i]) tarjan(i); flag=0; for (i=0;i<n;i++) if (col[(i<<1)^1]==col[i<<1]) { flag=1; break; } if (flag) printf("the evil panda is lying again "); else printf("panda is telling the truth... "); } return 0; }
H POJ 1743
思路:首先想到用差分来判断题目要求的重复旋律,接着只要找出差分数组中出现了两次的不重叠子串即可。
但是要注意一点,例如一串旋律为1 2 4 5 7,差分数组就是1 2 1 2,那么就可找出的字串1 2,但事实上124与467是重叠的。
二分子串长度x,每次二分判断就循环找到height不小于x的连续的i,记录sa[i]的最大值ma与最小值mi,通过判断ma-mi>=x判断两子串没有重叠。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxn 20010 using namespace std; int sa[maxn],rk[maxn],height[maxn],tmp[maxn],n,k; char s[maxn],a[maxn]; bool cmp_sa(int i,int j) { if (rk[i]!=rk[j]) return rk[i]<rk[j]; int ri=(i+k<n)?rk[i+k]:-1; int rj=(j+k<n)?rk[j+k]:-1; return ri<rj; } void get_sa() { int i; for (i=0;i<=n;i++) { sa[i]=i; rk[i]=s[i]; } for (k=1;k<=n;k<<=1) { sort(sa,sa+n,cmp_sa); tmp[sa[0]]=0; for (i=0;i<n;i++) tmp[sa[i+1]]=tmp[sa[i]]+(cmp_sa(sa[i],sa[i+1])?1:0); for (i=0;i<n;i++) rk[i]=tmp[i]; } } void get_height() { int i,j,k=0; for (i=0;i<n;i++) { if (k) k--; if (rk[i]>=1) j=sa[rk[i]-1]; while (s[i+k]==s[j+k] && i+k<n && j+k<n) k++; height[rk[i]]=k; } } int check(int x) { int ma=sa[1],mi=sa[1],i; for (i=2;i<=n;i++) { if (height[i]>=x && i<n) { ma=max(ma,sa[i]); mi=min(mi,sa[i]); } else { if (ma-mi>=x) return 1;//判断两段旋律不会重合 ma=sa[i];mi=sa[i]; } } return 0; } int query(int l,int r) { int mid; while (l<r) { mid=(l+r+1)>>1; if (check(mid)) l=mid; else r=mid-1; } l++; if (l>=5) return l; return 0; } int main() { int i; while (scanf("%d",&n)!=EOF && n!=0) { for (i=0;i<n;i++) scanf("%d",&a[i]); n--; for (i=0;i<n;i++) s[i]=a[i+1]-a[i]; get_sa(); get_height(); printf("%d ",query(0,n)); } return 0; }