zoukankan      html  css  js  c++  java
  • HIT暑期集训 2-SAT与后缀三连

    后缀数组详解

    后缀数组,倍增求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;
    }
    模板题 UOJ#35. 后缀排序

     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;
    }
    模板题 HDU-3062 Party

     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;
    }
    模板题 UVA 1391 Astronauts

     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;
    }
    View Code

    E    UVA 11107

    G    LibreOJ 2033

    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;
    }
    View Code
  • 相关阅读:
    dedecms5.7安装百度(ueditor)编辑器的方法
    shell多线程之进程间通信(2)
    shell多线程之进程间通信
    awk笔记
    用shell做简单的分布式计算
    C语言实现常用查找算法——二分查找
    C语言实现常用排序算法——基数排序
    C语言实现常用数据结构——堆
    C语言实现常用数据结构——图
    C语言实现常用数据结构——二叉查找树
  • 原文地址:https://www.cnblogs.com/lsykk/p/13606037.html
Copyright © 2011-2022 走看看