[SDOI2016]sequence 解题报告

考场上一直在试图调t3常数。。还有1.5h的时候才看到这个题,感觉是个很麻烦的网络流,强行写想起R1网络流写跪的经历还是写了暴力。。
然而暴力写起来并不比标算好写,考场上写残了好多地方。
要是一上来先切3h这题就好了。。24.

doc题解没认真听。。
说一下我的想法。
最蛋疼的地方在于处理字符串,要先把每行列中回文串删掉。注意到每个行列只有两种选择,这显然是对应网络流中属于S或T。然后每行列建一个点,属于S集表示这一行列中的单词的反串大于原单词,属于T集表示反之。强制属于的就直接与源汇连正无穷。然后每个单词建两个点a,b,之间是容量为1的单向边(a->b),每个有这个单词的行列向a连 /1,b向行列连 /1,表示如果有两个行列一个选S一个选T,就必须要割掉1。然后最大流*2+回文串就是答案。
主要是处理字符串比较麻烦。。代码一大半都是在搞字符串。
代码:

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
const int N=72+5;
char a[N][N];
int s[N<<1][N];
string hsh[N*N];
int obj[N*N];
int state[N<<1];

const int V=(N<<1)+(N*N*3);
const int E=(N<<1)+(N*N*3);
const int inf=0x7fffffff;
struct ES{
    int from,to,cap;
}e[E<<1];
int etot;
int nxt[E<<1],ptr[V];
int onxt[E<<1],optr[V];
void addedge(int from,int to,int cap){
    nxt[etot]=ptr[from],ptr[from]=etot;
    onxt[etot]=optr[to],optr[to]=etot;
    e[etot++]=(ES){from,to,cap};

    //if(cap)printf("addedge(%d,%d,%d)\n",from,to,cap);
}
int q[V],path[V],cur[V],dis[V],gap[V];
int isap(int snk){
    int src=snk-1;
    memset(dis,127,sizeof(dis));
    q[0]=snk,dis[snk]=0;
    for(int h=0,t=1;h!=t;++h)
        for(int i=optr[q[h]];i;i=onxt[i])
            if(e[i].cap&&dis[e[i].from]>1e9)
                ++gap[dis[q[t++]=e[i].from]=dis[q[h]]+1];
    for(int i=snk;i;--i)cur[i]=ptr[i];
    if(dis[src]>1e9){
        //puts("Discon!");
        return 0;
    }
    for(int ans=0;;){
        for(int node=src,i;node!=snk;){
            for(i=cur[node];i;i=nxt[i])
                if(e[i].cap&&dis[e[i].to]==dis[node]-1){
                    cur[node]=i;
                    path[node=e[i].to]=i;
                    break;
                }
            if(!i){
                if(--gap[dis[node]]==0)return ans;
                dis[node]=snk;
                for(int i=ptr[node];i;i=nxt[i])
                    if(e[i].cap&&dis[e[i].to]<dis[node])
                        dis[node]=dis[e[cur[node]=i].to];
                ++gap[++dis[node]];
                if(node!=src)node=e[path[node]].from;
            }
        }
        for(int node=snk;node!=src;node=e[path[node]].from)--e[path[node]].cap,++e[path[node]^1].cap;
        ++ans;

        //for(int node=snk;node!=src;node=e[path[node]].from)printf("%d ",node);
        //printf("%d\n",src);
    }
}
int main(){
    freopen("sentence.in","r",stdin);
    freopen("sentence.out","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)scanf("%d",state+i);
        for(int j=1;j<=m;++j)scanf("%d",state+n+j);
        for(int i=1;i<=n;++i)scanf("%s",a[i]+1);

        string tmp;
        int htot=0;
        hsh[0]="";
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j)
                if(a[i][j]!='_')hsh[htot]+=a[i][j];
                else
                    if(hsh[htot]!="")
                        hsh[++htot]="";
            if(hsh[htot]!="")hsh[++htot]="";

            for(int j=m;j;--j)
                if(a[i][j]!='_')hsh[htot]+=a[i][j];
                else
                    if(hsh[htot]!="")
                        hsh[++htot]="";
            if(hsh[htot]!="")hsh[++htot]="";
        }
        for(int j=1;j<=m;++j){
            for(int i=1;i<=n;++i)
                if(a[i][j]!='_')hsh[htot]+=a[i][j];
                else
                    if(hsh[htot]!="")
                        hsh[++htot]="";
            if(hsh[htot]!="")hsh[++htot]="";

            for(int i=n;i;--i)
                if(a[i][j]!='_')hsh[htot]+=a[i][j];
                else
                    if(hsh[htot]!="")
                        hsh[++htot]="";
            if(hsh[htot]!="")hsh[++htot]="";
        }
        sort(hsh,hsh+htot);
        htot=unique(hsh,hsh+htot)-hsh;
        for(int i=htot;i--;){
            tmp="";
            for(int j=hsh[i].size();j--;)tmp+=hsh[i][j];
            obj[i]=lower_bound(hsh,hsh+htot,tmp)-hsh;
        }

        int now=0;
        for(int i=htot;i--;)
            if(i==obj[i])
                ++now;
        int x;
        memset(s,0,sizeof(s));
        tmp="";
        for(int i=1;i<=n;++i){
            //printf("---%d---\n",i);
            for(int j=1;j<=m;++j)
                if(a[i][j]!='_')tmp+=a[i][j];
                else
                    if(tmp!=""){
                        x=lower_bound(hsh,hsh+htot,tmp)-hsh;
                        if(x!=obj[x]){
                            s[i][++s[i][0]]=x;
                            //cout<<"Get:"<<tmp<<endl;
                        }
                        tmp="";
                    }
            if(tmp!=""){
                x=lower_bound(hsh,hsh+htot,tmp)-hsh;
                //cout<<x<<endl; 
                if(x!=obj[x]){
                    s[i][++s[i][0]]=x;
                    //cout<<"Get:"<<tmp<<endl;
                }
                tmp="";
            }
        }
        for(int j=1;j<=m;++j){
            for(int i=1;i<=n;++i)
                if(a[i][j]!='_')tmp+=a[i][j];
                else
                    if(tmp!=""){
                        x=lower_bound(hsh,hsh+htot,tmp)-hsh;
                        if(x!=obj[x])s[n+j][++s[n+j][0]]=x;
                        tmp="";
                    }
            if(tmp!=""){
                x=lower_bound(hsh,hsh+htot,tmp)-hsh;
                if(x!=obj[x])s[n+j][++s[n+j][0]]=x;
                tmp="";
            }
        }
        n+=m;
        for(int i=1;i<=n;++i)
            if(s[i][1]>obj[s[i][1]]){
                state[i]=-state[i];
                for(int j=s[i][0];j;--j)s[i][j]=obj[s[i][j]];
            }

        /*printf("hsh:");
        for(int i=0;i<htot;++i)cout<<hsh[i]<<" ";
        puts("");
        for(int i=1;i<=n;++i){
            printf("%d(%d):",i,state[i]);
            for(int j=1;j<=s[i][0];++j)printf("%d ",s[i][j]+1);
            puts("");
        }*/

        etot=2;
        memset(ptr,0,sizeof(ptr)),memset(optr,0,sizeof(optr));
        int src=n+1+(htot<<1),snk=n+1+(htot<<1)+1;
        for(int i=1;i<=n;++i){
            if(state[i]==1){
                addedge(src,i,inf);
                addedge(i,src,0);
            }
            else if(state[i]==-1){
                addedge(i,snk,inf);
                addedge(snk,i,0);
            }
            for(int j=s[i][0];j;--j){
                addedge(i,n+1+s[i][j],1);
                addedge(n+1+s[i][j],i,0);

                addedge(n+1+s[i][j]+htot,i,1);
                addedge(i,n+1+s[i][j]+htot,0);
            }
        }
        for(int i=htot;i--;){
            addedge(n+1+i,n+1+i+htot,1);
            addedge(n+1+i+htot,n+1+i,0);
        }
        printf("%d\n",now+(isap(snk)<<1));
    }
}

总结:
①考试的时候一定要多想想再写:错误、正确性、怎么样写简单。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值