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;
}
2、hdu4763
題意:在所給字符串中尋找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;
}
3、hdu2594
題意:給出字符串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;
}
4、hdu3746
題意:字符串中任意字符必須以“段“的形式重覆兩次,問最少需要添加幾個字符。
題解: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;
}
5、poj1151
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;
}
6、poj1177
題意:求矩形周長並
{待補)