[FZU1540 迎接光棍节]枚举+KMP Or 二分+后缀数组

【题目】多串的最长等差连续子串。中文题目:http://acm.fzu.edu.cn/problem.php?pid=1540

【算法分析】

这个作为后缀数组的经典例题之一。。。就不用说了。。。

但是很囧的是,我写的后缀数组MLE了= =。由于我的后缀数组特别搓,所以套模板的人们应该都可以过。

注意到这题的特殊性,n<=4000,每个串长<=200。

所以可以有一个暴力解法。

先等差处理。(a[i]-a[i-1])

然后枚举答案在串1中开始的位置。

于是以第一个串从枚举的开始位置到第一个串末端作为模式串。

去和n-1个串暴力KMP匹配。可以得到最多能配多长。

然后就能过了。

【时间复杂度】O(Len*Sum) Len为第一个串的长度。Sum为所有串的字母数之和。

【空间复杂度】O(Sum)

【CODE】

#include

[SGU176 Flow construction]【最小流】

【题目大意】
给定源汇,一些弧必须满载。问源到汇的最小流是多少?
【算法分析】
通过加弧当然。。。这是最简单的方法。。。反向增广这么高科技的就算了。。。
【其它】
复习上下界网络流。居然没1Y。原因1是有一个地方N写成E了。(就是数组没开够。。。),原因2是MLE。
我的习惯一直是把数组开大很多的。。。SGU这种限这么死的地方就果断悲剧。
【CODE】
#include #include #include const int N=155;
const int E=N*N*6;
struct edge{int x,y,c,next;};

struct Network_t{
    int e,S,T,Flow;
    edge g[E];
    int ls[N],fa[N],cur[N],num[N],d[N];
    void init(){
        e=1;
        memset(ls,0,sizeof(ls));
    }

    void clr(){
        for (int i=3;i<=e;i+=2){
            g[i-1].c+=g[i].c;
            g[i].c=0;
        }
    }

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

    void relabel(int k){
        cur[k]=ls[k];
        int mm=T;
        for (int t=ls[k];t;t=g[t].next)
          if (g[t].c && d[g[t].y]            mm=d[g[t].y];
        d[k]=mm+1;
    }

    void change(){
        int nf=0x7FFFFFFF;
        for (int i=T;i!=S;i=g[fa[i]].x)
          if (g[fa[i]].c        for (int i=T;i!=S;i=g[fa[i]].x){
            g[fa[i]].c-=nf;
            g[fa[i]^1].c+=nf;
        }
        Flow+=nf;
    }

    void sap(){
        Flow=0;
        int i;
        for (i=1;i<=T;i++){
            d[i]=num[i]=0;
            cur[i]=ls[i];
        }
        i=S;
        while (d[S]            int &t=cur[i];
            for (;t;t=g[t].next)
              if (g[t].c && d[g[t].y]+1==d[g[t].x]) break;
            if (t){
                fa[g[t].y]=t;
                i=g[t].y;
                if (i==T){
                    change();
                    i=S;
                }
            }
            else{
                if (!–num[d[i]]) break;
                relabel(i);
                ++num[d[i]];
                if (i!=S) i=g[fa[i]].x;
            }
        }
    }
}Network;

int n,m,SF;
int din[N],dout[N],Type[E],C[E];

void init(){
    Network.init();
    scanf("%d%d",&n,&m);
    SF=0;
    for (int x,y,c,t,i=1;i<=m;i++){
      scanf("%d%d%d%d",&x,&y,&c,&t);
      if (t){
          din[y]+=c;
          dout[x]+=c;
          SF+=c;
      }
      else Network.addedge(x,y,c);
      Type[i]=t;
      C[i]=c;
    }
}

void build(){
    Network.S=n+1; Network.T=n+2;
    int i;
    for (i=1;i<=n;i++){
        if (din[i]) Network.addedge(n+1,i,din[i]);
        if (dout[i]) Network.addedge(i,n+2,dout[i]);
    }
    Network.addedge(n,1,0x7FFFFFFF);
}

void output(){
    int cnt=1;
    for (int i=1;i<=m;i++){
      if (Type[i]) printf("%d",C[i]);
      else printf("%d",Network.g[cnt+=2].c);
      if (i==m) puts("");
           else putchar(‘ ’);
    }
}

void solve(){
    Network.sap();
    if (Network.Flow!=SF){
        puts("Impossible");
        return;
    }
    int l,r,mid;
    l=0; r=Network.g[Network.e].c;
    while (l        mid=(l+r)/2;
        Network.clr();
        Network.g[Network.e-1].c=mid;
        Network.sap();
        if (Network.Flow==SF) r=mid;
                         else l=mid+1;
    }
    Network.clr();
    Network.g[Network.e-1].c=l;
    Network.sap();
    printf("%dn",l);
    output();
}

int main(){
    init();
    build();
    solve();
    return 0;
}

[SGU187 Twist and whirl – want to cheat]【Splay】

【题目大意】

给定一个1~n的排列,每次操作会将[l,r]这个区间上的数翻转。问到最后,整个排列变成个什么样?

【算法分析】

就是Splay加个翻转操作啦。。。非常easy。用来增加自信心。。。。

属于被秒杀题类型。。。

【时间复杂度】O(m lg n)

【空间复杂度】O(n)

【其它】1Y。

【CODE】

#include

[POJ3764 The xor-longest Path]【异或运算】【Trie树】

【题目大意】给定一棵树,然后一条树的路径的权和定义为路径上边权全部xor之后得出的值

【算法分析】树的话。设d[x]为从根到x这条路径的权。那么两点间的路径权就是d[x] xor d[y]。(LCA到根部分被两次xor抵消啦),然后就转化为给定n个数,求d[x]^d[y]最大。这个就和USACO第6章那个cowxor一模一样啦。利用Trie树求解。

【时间复杂度】O(30*N)

【空间复杂度】O(30*N)

【其它】1Y。在lcc大神空间看到有这题,然后一看题目。。。Orz,再次见面的题目就成水题啦。。。睡前一水。

【CODE】

#include #include #include const int N=100005; struct edge{int y,w;edge *next;}g[N*2],*ls[N]; int n,e,tot; int d[N],L[N],v[N],ch[N*32][2];
void addedge(int x,int y,int w){       g[++e].y=y; g[e].w=w; g[e].next=ls[x]; ls[x]=&g[e];       g[++e].y=x; g[e].w=w; g[e].next=ls[y]; ls[y]=&g[e]; }
void init(){      int i,x,y,w;      for (e=i=0;i     for (i=1;i          scanf("%d%d%d",&x,&y,&w);           addedge(x,y,w);       } }
void bfs(){      int i,head=-1,tail=0;      for (i=0;i      v[0]=1; L[0]=d[0]=0;      while (head!=tail){             head++;            for (edge *t=ls[L[head]];t;t=t->next)              if (!v[t->y]){                 d[t->y]=d[L[head]]^t->w;                 v[t->y]=1;                 L[++tail]=t->y;               }       } }
void Insert(int x){      int s,p,t;      for (p=1,s=30;s>=0;s--){         t=( (1<       if (!ch[p][t]){           ch[p][t]=++tot;           ch[tot][0]=ch[tot][1]=0;         }         p=ch[p][t];       } }
int Get(int x){     int res=0,s,p,t;     for (p=1,s=30;s>=0;s--){        t=( (1<      if (ch[p][!t]) {p=ch[p][!t]; res|=!t<                else {p=ch[p][t];   res|= t<     }     return res^x; }
void work(){       tot=1;       ch[1][0]=ch[1][1]=0;       Insert(d[0]);      int i,ans=0,now;      for (i=1;i          now=Get(d[i]);          if (now>ans) ans=now;           Insert(d[i]);       }       printf("%dn",ans); }
int main(){     while (scanf("%d",&n)!=EOF){            init();            bfs();            work();      } }

[HDOJ1423 Greatest Common Increasing Subsequence]【最长公共上升子序列】

【算法分析】裸的dp。时间复杂度 O(mn)。空间复杂度 O(m+n)。

【其它】今天有人问我。。。于是就做了。= =,我还恶趣味地把代码压短了。。。搞到434B。大家不要鄙视我。。。起码还是有层次感的。。。不是恶意压行那种。。。

【CODE】

#include using namespace std; int m,n,T,k,i,j,r,p,a[505],b[505],F[505]; int main(){      cin>>T;     for (k=1;k<=T;k++){       for (cin>>m,i=0;i      for (cin>>n,i=0;i      for (r=p=0,i=0;i        for (j=0;j           p>?=b[j]           F[j]>?=a[i]==b[j]?p+1:0;          }        cout<       k!=T?puts(""):0;      } }