[ZOJ 3298 Crack]KMP

【题目大意】

给一个串A,一个串B,然后在B串中,从A串的某个位置开始匹配,然后匹配到A串末尾又匹配回A串开头,然后问最长的匹配段是多少?

如果A串在B串中没有一个正常的从1开始的匹配的话,输出bad。

【算法分析】

当时没想到,经lcc教导,终于明白了。。。ORZ!

先KMP。

我是开了一个邻接表,记录连续的完全匹配。

然后给每一个连续的完全匹配向前和向后延伸。然后去更新ans即可。

【CODE】

#include #include struct gtp{int y,next;}g[1001111];
int m,n,e;
int next[1111];
int P[1111],T[1001111];
int tot;
int belong[1001111],ls[1001111];

void makenext(){
    next[1]=0;
    int i,j=0;
    for (i=2;i<=m;i++){
        while (j>0 && P[j+1]!=P[i]) j=next[j];
        if (P[j+1]==P[i]) j++;
        next[i]=j;
    }   
}   

inline void addedge(int &x,int &y){
    e++;
    g[e].y=y; g[e].next=ls[x]; ls[x]=e;
}   

void kmp(){
    for (int i=1;i<=n;i++){
        belong[i]=0;
        ls[i]=0;
    }   
    tot=0;
    e=0;
    int i,j=0;
    for (i=1;i<=n;i++){
        while (j>0 && P[j+1]!=T[i]) j=next[j];
        if (P[j+1]==T[i]) j++;
        if (j==m){
            if (!belong[i-m]){
                tot++;
                belong[i]=tot;
            }
            else belong[i]=belong[i-m];
            addedge(belong[i],i);
            j=next[j];
        }   
    }   
}

void solve(){
    if (tot==0){
        printf("badn");
        return;
    }   
    int i,j,k,t,now,ans=0,num,st;
    for (i=1;i<=tot;i++){
        j=g[ls[i]].y+1;
        k=1;
        while (j<=n && k<=m && P[k]==T[j]){j++; k++;}
        j–; k–;
        now=k; num=0;
        for (t=ls[i];t;t=g[t].next){num++;st=g[t].y-m;}
        now+=m*num;
        j=st; k=m;
        while (j>=1 && k>=1 && P[k]==T[j]){j–; k–;}
        now+=m-k;
        if (now>ans) ans=now;
    }   
    printf("%dn",ans);
}   

int main(){
    for (;;){
        if (scanf("%d%d",&m,&n)==EOF) break;
        for (int i=1;i<=m;i++) scanf("%d",&P[i]);
        for (int i=1;i<=n;i++) scanf("%d",&T[i]);
        makenext();
        kmp();
        solve();
    }   
}   

ZOJ月赛——2010.2.21

【比赛经历】

这次月赛比较纠结,我大概1点半才开始做

然后一开始见到I题好多人A啊,然后就做I题去了,WA个不停。。。

最后发现,理解错了题目了,ORZ。。。于是重敲以后一交,AC。

无无聊聊的看了一下C题,不会做~

然后出来一看,F题AC人数暴增!

直接切进去,OH YEAH,原来是个排序+贪心,好像差不多10行的样子写完,交上去AC了。

回头看B题,AC人数也挺多的,再次切进去,然后看不懂continuous subsequence的意思。

金山词霸显示:n. 后继,随后

囧,到群里问了下,被痛斥了一下。。。终于知道连续子序列的意思。

然后仔细一思考,我只要搞到它满足所有的min,然后判断有没有超过max的即可。

所以如果只是想搞到他满足所有的min的话,用首尾指针维护即可。

一交,1A。

然后又去看了比较多人A的E题。哇。。。GDKOI出过这题的类似加强版!

于是就开敲,发现数据规模非常小,不需要用GDOI那种N^2的方法,直接DFS就行。

一交,居然WA了。。。检查了半天,发现是题目要求输出所有方案,而不是一个方案。。。囧。

改了以后终于AC。

然后剩下的时间已经不够8分钟了。索性不做,围观其他神牛。。。

最后rank:28

很大程度是因为睡懒觉。。。否则时间应该前移很多,5题也是有可能的。

rank围观地址:http://acm.zju.edu.cn/onlinejudge/showContestRankList.do?contestId=305

额,感叹一下,漆子超太无敌了。。。他还是单挑的。。。

表示对各路神牛的YM!

[UASCO 6.1.2 Serious challenges]动态规划

【算法分析】

这题我做过类似的,基本思想是做垂线,然后向左右延伸。

算法步骤的思想如下:

枚举每一个点,然后尽量向上延伸,直到碰到墙壁或者坏了的点,然后将垂直的线段向左右尽量延伸,最后结果就在这M*N个极大子矩形当中。

这个算法很容易证明:如果是答案的子矩阵,那么它一定上下左右都被某个点(或边界)卡住,否则他还可以延伸就不是最大的了。然后这个算法把每一个格子当做是最大矩形的上顶点(即阻止它向上延伸的顶点),然后向下延伸任意长度的各种情况都枚举了,那么向左右延伸,就必然可以包含最优解。

最后利用DP的思想减少重复,复杂度达到O(RC),使用滚动数组空间复杂度达到O(C)

【其它】

这题搞死我了,一直WA at 10,然后用pascal写了一遍,又是WA at 10

于是搞来搞去,最后发现原来是一个地方没有初始化,一交,终于AC,ORZ!!!

USACO终于圆满了,在此纪念一下

Chapter 1 DONE 2009.08.29 Getting started Chapter 2 DONE 2007.08.09 Bigger Challenges Chapter 3 DONE 2008.07.22 Techniques more subtle Chapter 4 DONE 2008.08.05 Advanced algorithms and difficult drills Chapter 5 DONE 2010.02.19 Serious challenges Chapter 6 DONE 2010.02.20 Contest Practice

这时间差好恐怖。。。

【CODE】

/*
ID:jie22221
TASK:rectbarn
LANG:C++
*/
#include #include #define min(x,y) (x)<(y)?(x):(y)
#define max(x,y) (x)>(y)?(x):(y)
const int INF=0x7FFFFFFF/5;
struct zb{int x,y;}s[31111];
int m,n,p,ans=0;
int u[2][3111],l[2][3111],r[2][3111],ll[3111],rr[3111];
bool v[2][3111];

void sort(int L,int R){
    if (L>=R) return;
    zb mid=s[(L+R)/2],tmp;
    int i=L,j=R;
    while (i        while (s[i].x        while (s[j].x>mid.x || s[j].x==mid.x && s[j].y>mid.y) j–;
        if (i<=j){
            tmp=s[i]; s[i]=s[j]; s[j]=tmp;
            i++; j–;
        }
    }
    sort(L,j);
    sort(i,R);
}

void init(){
    memset(s,0,sizeof(s));
    scanf("%d%d%dn",&m,&n,&p);
    for (int i=0;i      scanf("%d%dn",&s[i].x,&s[i].y);
    sort(0,p-1);
    for (int i=0;i<=n+1;i++){
        v[0][i]=true;
        l[0][i]=INF;
        r[0][i]=INF;
    }
}

void work(){
    int si=0,i,j,R,pi,tmp;
    for (R=1;R<=m;R++){
        i=R&1; pi=i^1;
        memset(v[i],false,sizeof(v[i]));
        v[i][0]=true; v[i][n+1]=true;
        for (j=1;j<=n;j++)
          while (si

              si++;
              v[i][j]=true;
          }
//      deal ll
        for (j=1;j<=n;j++)
          if (!v[i][j])
            if (v[i][j-1]) ll[j]=0;
                      else ll[j]=ll[j-1]+1;
//      deal rr
        for (j=n;j>=1;j–)
          if (!v[i][j])
            if (v[i][j+1]) rr[j]=0;
                      else rr[j]=rr[j+1]+1;
//      dp
        for (j=1;j<=n;j++)
          if (!v[i][j]){
              if (v[pi][j]){
                  u[i][j]=0;
                  l[i][j]=ll[j];
                  r[i][j]=rr[j];
              }
              else{
                  u[i][j]=u[pi][j]+1;
                  l[i][j]=min(ll[j],l[pi][j]);
                  r[i][j]=min(rr[j],r[pi][j]);
              }
              tmp=(l[i][j]+r[i][j]+1)*(u[i][j]+1);
              if (tmp>ans)
                ans=tmp;
          }
    }
}

int main(){
    freopen("rectbarn.in","r",stdin);
    freopen("rectbarn.out","w",stdout);
    init();
    work();
    printf("%dn",ans);
}

[USACO 6.1.1 Postal Vans]高精度、找规律

【题目大意】找一个特殊图哈密顿回路的方案数。

【算法分析】

我先DFS了一下,感觉如果列是4的话,应该是一个4阶的递归式。

然后找到规律。。。OH,YEAH,AC

规律就是F[n]=2F[n-1]+2F[n-2]-2F[n-3]+F[n-4]

【其它】1A

【CODE】

/*
ID:jie22221
TASK:vans
LANG:C++
*/
#include #include const int M=100;
const int Mod=100000;
struct bigint{int d[M+1];};
int px[4]={-1,1,0,0},py[4]={0,0,1,-1};
int n,limit,total,ans;
bigint f[1001];
bool v[5][5];

void dfs(int x,int y){
    if (total==4*limit-1){
        if (x+y==3) ans++;
        return;
    }
    int k,tx,ty;
    v[x][y]=true;
    total++;
    for (k=0;k<4;k++){
        tx=x+px[k]; ty=y+py[k];
        if (tx<1 || tx>4 || ty<1 || ty>limit || v[tx][ty]) continue;
        dfs(tx,ty);
    }   
    v[x][y]=false;
    total–;
}   

bigint plus(bigint x,bigint y){
    for (int i=1;i<=M;i++) x.d[i]+=y.d[i];
    for (int i=M;i>=1;i–){
        x.d[i-1]+=x.d[i]/Mod;
        x.d[i]%=Mod;
    }   
    return x;
}

bigint dec(bigint x,bigint y){
    for (int i=1;i<=M;i++) x.d[i]-=y.d[i];
    for (int i=M;i>=1;i–)
      while (x.d[i]<0){
          x.d[i]+=Mod;
          x.d[i-1]–;
      }   
    return x;
}   

void init(){
    memset(f,0,sizeof(f));
    for (limit=1;limit<=4;limit++){
        ans=0;
        total=0;
        dfs(1,1);
        f[limit].d[M]=ans;
    }
}

void put(bigint x){
    int st;
    for (st=0;st<=M;st++)
      if (x.d[st]) break;
    printf("%d",x.d[st]);
    for (int i=st+1;i<=M;i++){
        int div=Mod/10,mod=Mod;
        while (div>0){
            printf("%d",x.d[i]%mod/div);
            mod/=10;
            div/=10;
        }   
    }   
    printf("n");
}   

void work(){
    scanf("%d",&n);
    if (n<=4){
        printf("%dn",f[n].d[M]);
        return;
    }
    bigint tmp;
    for (int i=5;i<=n;i++){
       memset(tmp.d,0,sizeof(tmp.d));
       tmp=plus(f[i-1],f[i-1]);
       f[i]=plus(f[i],tmp);
       tmp=plus(f[i-2],f[i-2]);
       f[i]=plus(f[i],tmp);
       tmp=plus(f[i-3],f[i-3]);
       f[i]=dec(f[i],tmp);
       f[i]=plus(f[i],f[i-4]);
    }
    put(f[n]);
}   

int main(){
    freopen("vans.in","r",stdin);
    freopen("vans.out","w",stdout);
    init();
    work();
}   

[USACO 5.3 Window Area]矩形切割

【题目翻译】http://www.wzoi.org/usaco/15%5C305.asp

【算法分析】

矩形切割,直接模拟就可以。

【其它】囧,以前居然卡在这题水题上。1A

USER: wei jie chen [jie22221]TASK: windowLANG: C++Compiling…Compile: OKExecuting… Test 1: TEST OK [0.000 secs, 2804 KB] Test 2: TEST OK [0.000 secs, 2804 KB] Test 3: TEST OK [0.000 secs, 2804 KB] Test 4: TEST OK [0.011 secs, 2804 KB] Test 5: TEST OK [0.011 secs, 2804 KB] Test 6: TEST OK [0.011 secs, 2804 KB] Test 7: TEST OK [0.022 secs, 2804 KB] Test 8: TEST OK [0.022 secs, 2804 KB] Test 9: TEST OK [0.000 secs, 2804 KB] Test 10: TEST OK [0.000 secs, 2804 KB] Test 11: TEST OK [0.022 secs, 2804 KB]All tests OK.

YOUR PROGRAM (‘window’) WORKED FIRST TIME! That’s fantastic– and a rare thing. Please accept these special automatedcongratulations.

【CODE】

/*
ID:jie22221
TASK:window
LANG:C++
*/
#include #include #include #include #include using namespace std;
const int N=100;
struct zfx{int x1,y1,x2,y2;char mark;}d[N];
int n;
double ans;inline int area(int x1,int y1,int x2,int y2){
    return (x2-x1)*(y2-y1);
}    void cut(int i,int x1,int y1,int x2,int y2){
    if (x1>=x2 || y1>=y2) return;
    if (i>n){
        ans+=area(x1,y1,x2,y2);
        return;
    }   
    if (x1    if (x2>d[i].x2) cut(i+1,max(x1,d[i].x2),y1,x2,y2);
    if (y1    if (y2>d[i].y2) cut(i+1,max(x1,d[i].x1),max(d[i].y2,y1),min(x2,d[i].x2),y2);
}   int main(){
    freopen("window.in","r",stdin);
    freopen("window.out","w",stdout);
    char op;
    int pos;
    zfx tmp;
    for (;;){
        op=’ ‘;
        while (scanf("%c",&op)!=EOF && (op==’ ‘ || op==’n’));
        if (op==’ ‘ || op==’n’) break;
        switch (op){
            case ‘w’:
                n++;
                scanf("(%c,%d,%d,%d,%d)",&d[n].mark,&d[n].x1,&d[n].y1,&d[n].x2,&d[n].y2);
                if (d[n].x1>d[n].x2) swap(d[n].x1,d[n].x2);
                if (d[n].y1>d[n].y2) swap(d[n].y1,d[n].y2);
                break;
            case ‘t’:
                scanf("(%c)",&op);
                zfx tmp;
                for (pos=1;pos<=n;pos++)
                  if (d[pos].mark==op) break;
                tmp=d[pos];
                for (int i=pos;i                d[n]=tmp;
                break;
            case ‘b’:
                scanf("(%c)",&op);
                for (pos=1;pos<=n;pos++)
                  if (d[pos].mark==op) break;
                tmp=d[pos];
                for (int i=pos;i>1;i–) d[i]=d[i-1];
                d[1]=tmp;
                break;
            case ‘d’:
                scanf("(%c)",&op);
                for (pos=1;pos<=n;pos++)
                  if (d[pos].mark==op) break;
                for (int i=pos;i                n–;
                break;
            case ‘s’:
                scanf("(%c)",&op);
                for (pos=1;pos<=n;pos++)
                  if (d[pos].mark==op) break;
                ans=0;
                cut(pos+1,d[pos].x1,d[pos].y1,d[pos].x2,d[pos].y2);
                double S=area(d[pos].x1,d[pos].y1,d[pos].x2,d[pos].y2);
                printf("%.3lfn",ans/S*100);
                break;
        }   
    }   
}