1、hdu3336
题意:相同前缀的次数和。
题解:利用了KMP中next数组的含义,从j直接跳到next[j]的原因是next[j]~j中不会再有和1~j中的相同前缀。
next[i]表示了模式串p[1~i-1]中最大的相同的前缀和后缀的长度。
PS:关于KMP的具体讲解 请看这篇文章,http://blog.csdn.net/v_july_v/article/details/7041827
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e8 using namespace std; char s[2000000]; int nxt[2000000]; int MOD=10007; void get(){ int i=0,j=-1; nxt[0]=-1; while (s[i]!='\0'){ if (j==-1 || s[j]==s[i]){ i++,j++; nxt[i]=j; } else j=nxt[j]; } } int main(){ int T,len,ans; scanf("%d",&T); while (T--){ memset(nxt,0,sizeof(nxt)); scanf("%d %s",&len,s); get(); ans=len; for (int i=1;i<=len;i++){ int tmp=nxt[i]; while (tmp){ ans=(ans+1)%MOD; tmp=nxt[tmp]; } } printf("%d\n",ans); } return 0; }
题意:在所给字符串中寻找E···E···E形式的最长E。
题解:根据next数组的意义next[len]满足的串形式首尾相同,即在剩下的串种寻找相同的子串,可以适当缩小子串长度。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e8 using namespace std; const int MAXN = 1000100; char str[MAXN]; char tmp[MAXN]; int nextval[MAXN]; int len; void get(char *s,int lenth){ int i=0,j=-1; nextval[0]=-1; while (i<lenth){ if (j==-1 || s[i]==s[j]){ i++; j++; if(s[i]!=s[j]) nextval[i]=j; else nextval[i]=nextval[j]; } else j=nextval[j]; } return ; } bool KMP(char *t,char *s,int lenth,int lenn){ int i=0,j=0; while (j<lenn){ if (i==-1 || s[j]==t[i]){ i++; j++; if (i==lenth) return 1; } else i=nextval[i]; } return 0; } int main(){ int T; scanf("%d",&T); while (T--){ scanf("%s",str); len=strlen(str); get(str,len); int ans=nextval[len]; while (ans>len/3) ans=nextval[ans]; while (ans>0){ if (KMP(str,&str[ans],ans,len-ans-ans)) break; ans=nextval[ans]; } if (ans<0) printf("%d\n",len/3); else printf("%d\n",ans); } return 0; }
题意:给出字符串A,B,求A的前缀和B的后缀相同的最大长度。
题解:两个字符串中间添加一个不会出现的特殊符号,然后对合并后的串求一下next。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e8 using namespace std; void get(char *x,int m,int nxt[]){ int i=0,j=-1; nxt[0]=-1; while (i<m){ if (j==-1 || x[i]==x[j]){ i++,j++; if (x[i]!=x[j]) nxt[i]=j; else nxt[i]=nxt[j]; } else j=nxt[j]; } return ; } int nxt[100010]; int main(){ char str1[100010]; char str2[50010]; while (~(scanf("%s%s", str1, str2))){ int tmp1=strlen(str1); str1[tmp1]='&'; str1[tmp1+1]='\0'; strcat(str1,str2); int tmp=strlen(str1); memset(nxt,0,sizeof(nxt)); get(str1,tmp,nxt); if (nxt[tmp]){ for (int i=0;i<nxt[tmp];i++){ printf("%c",str1[i]); } printf(" "); printf("%d\n",nxt[tmp]); } else printf("%d\n",nxt[tmp]); } return 0; }
题意:字符串中任意字符必须以“段“的形式重覆两次,问最少需要添加几个字符。
题解:next数组的意义就是代表模式串中必须是成段对称,所以求个next然后根据重复的段长度求个%。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e8 using namespace std; const int N = 100002; char str[N]; int nxt[N]; void get(int len) { int i; int j=0; for(nxt[1]=0,i=2;i<=len;i++) { while(j && str[j+1]!=str[i]){ j=nxt[j]; } if(str[j+1]==str[i]){ j++; } nxt[i]=j; } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%s", str + 1); int len = strlen(str + 1); get(len); int x =len-nxt[len]; if(len%x==0 && len!=x){ printf("0\n"); } else{ printf("%d\n",x-nxt[len]%x); } } return 0; }
ACdreamer有一种非线段树的写法,不过分析了复杂度发现是递归的n^3复杂度。 在这里补上线段树的nlogn写法。
题意:求矩形面积并。
题解:扫描线+线段树。将矩形的竖边删掉,剩下的横匾按照y值排序,由小到大,每个矩形下端的边称之为入边,标记为+1,上端的边称之为出边,标记为-1。每个node节点维护当前这个区间内的被覆盖的长度,被标记的大小,即(+1-1+1-1)这种形式的和,以确定扫到了哪里。从下往上扫的时候,遇到+1则更新被覆盖长度,遇到-1则相乘并累加。
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-15 #define inf 1e8 using namespace std; #define lz 2*u,l,mid #define rz 2*u+1,mid+1,r const int maxn=4222; db sum[maxn]; db flag[maxn]; db X[maxn]; struct Node{ db lx, rx, y; int s; Node(){}; Node(db lx_,db rx_,db y_,db s_){ lx=lx_, rx=rx_, y=y_, s=s_; } bool operator <(const Node &S) const{ return y<S.y; } }line[maxn]; int find(db tmp,int n){ int l=1,r=n,mid; while (l<=r){ mid=(l+r)>>1; if (X[mid]==tmp) return mid; else if(X[mid]<tmp) l=mid+1; else r=mid-1; } } void pushup(int u ,int l,int r){ if (flag[u]) sum[u]=X[r+1]-X[l]; else if (l==r) sum[u]=0; else sum[u]=sum[2*u]+sum[2*u+1]; } void update(int u,int l,int r,int tl,int tr,int c){ if (tl<=l && r<=tr){ flag[u]+=c; pushup(u,l,r); return ; } int mid=(l+r)>>1; if (tr<=mid) update(lz,tl,tr,c); else if (tl>mid) update(rz,tl,tr,c); else { update(lz,tl,mid,c); update(rz,mid+1,tr,c); } pushup(u,l,r); } int main(){ int n,cas=0; while (~scanf("%d",&n),n){ int num=0; memset(flag,0,sizeof(flag)); memset(sum,0,sizeof(sum)); for (int i=1;i<=n;i++){ db x1,x2,y1,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); line[num++]=Node(x1,x2,y1,1); X[num]=x1; line[num++]=Node(x1,x2,y2,-1); X[num]=x2; } sort(X+1,X+1+num); sort(line+1,line+1+num); int k=1; for (int i=2;i<=num;i++) if (X[i]!=X[i+1]) X[++k]=X[i]; db ans=0; for (int i=1;i<num;i++){ int l=find(line[i].lx,k); int r=find(line[i].rx,k)-1; update(1,1,k,l,r,line[i].s); ans+=sum[1]*(line[i+1].y-line[i].y); } printf("Test case #%d\n",++cas); printf("Total explored area: %.2f\n\n",ans); } return 0; }
题意:求矩形周长并
{待补)