HDU5772 String problem

来源:互联网 发布:京东货到付款拒收 知乎 编辑:程序博客网 时间:2024/06/14 00:08

题目链接

题目大意

给定一个只包含阿拉伯数字的长度为n的字符串,现从中取出一个子序列,使得其价值最大.

定义一个子序列的价值为Value=val9i=0costi.
其中:

val=1im,1jm,ijw[idi][idj].

其中m为选出子序列的长度,idi为子序列的第i个字符在原字符串中的下标.

并且:

costi={0ai(ki1)+biki=0ki0

其中ki表示选出的子序列中数字i的出现次数.

0n100,0aibi103,0w[i][j]50.

题解

第一眼显然是神dp

dp的状态设计和转移都很难,需要好好分析一下这个答案的构成.

可以认为是选一条边(i,j)能得到的价值是w[i][j]+w[j][i],但选边的前提条件是必须选择它的两个顶点,而选择节点又会花费相应的代价.
而边的价值都是非负的,所以选的边是选出的点的导出子图的边集,这样按理说可以用胡伯涛论文中推导最大密度子图时用到的思路来构图求最小割求解.
但是这里还有一个问题,选定一个节点的代价并不是固定的,因为那个cost是一个分段函数.

那么我们只能考虑用比较low的方法,转化为最大权闭合图来做了.
那么也很容易能想到怎么处理那个分段函数了,只要新建代表每个数字的节点,选定一个节点的前提是要选择对应的数字节点,计算一下相应的代价即可.

这样构图的点数和边数都是O(n2)级别的,抱着对网络流复杂度的伟大信仰坚定地跑一发Dinic,AC还是没有压力的.

比赛时比较乱的代码

#include <cstdio>#include <cmath>#include <ctime>#include <cctype>#include <cstring>#include <cstdlib>#include <cassert>#include <set>#include <map>#include <queue>#include <vector>#include <bitset>#include <complex>#include <iostream>#include <algorithm>#define fi first#define se second#define pb push_back#define y1 kjfasiv#define lowbit(x) (x&-x)#define debug(x) cout<<#x<<"="<<x<<endl#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;typedef long long ll;typedef unsigned long long ull;typedef unsigned int uint;typedef pair<int,int> pii;typedef pair<ll,ll> pll;typedef vector<int> veci;typedef complex<double> Com;const int mod=(int)1e9+7,inf=(int)1e9,rx[]={-1,0,1,0},ry[]={0,1,0,-1};const ll INF=1ll<<60;const double pi=acos(-1.0),eps=1e-8;template<class T>void rd(T &res){    res=0;    char c;    while(c=getchar(),c<48);    do res=res*10+(c^48);        while(c=getchar(),c>47);}template<class T>void rec_print(T x){    if(!x)return;    rec_print(x/10);    putchar(x%10^48);}template<class T>void print(T x){    if(!x)putchar('0');    else rec_print(x);}template<class T>inline void Max(T &a,T b){    if(b>a)a=b;}template<class T>inline void Min(T &a,T b){    if(b<a)a=b;}inline void mod_add(int &a,int b){    if((a+=b)>=mod)a-=mod;}int fast_mod_pow(int a,int b){    int res=1;    for(;b;b>>=1,a=1ll*a*a%mod)        if(b&1)res=1ll*res*a%mod;    return res;}const int N=105,V=N*N+N+10,E=(int)1e6+5;int src,sink,tot_edge,// tot_edge=0;    dist[V],work[V],que[V],head[V];// memset(head,-1,sizeof(head));bool used[V];struct Edge{    int to,cap,nxt;}edge[E<<1];void add_edge(int from,int to,int c){    edge[tot_edge]=(Edge){to,c,head[from]};    head[from]=tot_edge++;    edge[tot_edge]=(Edge){from,0,head[to]};    head[to]=tot_edge++;}void bfs(){    int L=0,R=0;    for(int i=src;i<=sink;++i)        dist[i]=-1;    dist[que[R++]=src]=0;    while(L<R){        int cur=que[L++];        for(int i=head[cur];~i;i=edge[i].nxt){            int to=edge[i].to;            if(edge[i].cap&&dist[to]==-1){                dist[to]=dist[cur]+1;                que[R++]=to;            }        }    }}int dfs(int cur,int f){    if(cur==sink)return f;    used[cur]=true;    for(int &i=work[cur];~i;i=edge[i].nxt){        int to=edge[i].to;        if(!used[to]&&edge[i].cap&&dist[to]==dist[cur]+1){            int d=dfs(to,min(f,edge[i].cap));            if(d){                edge[i].cap-=d;                edge[i^1].cap+=d;                return d;            }        }    }    return 0;}int Dinic(){    int flow=0;    while(true){        bfs();        if(dist[sink]==-1)return flow;        for(int i=src;i<=sink;++i)            work[i]=head[i];        while(true){            for(int i=src;i<=sink;++i)                used[i]=false;            int f=dfs(src,inf);            if(!f)break;            flow+=f;        }    }}int a[N],b[N],w[N][N],id_edge[N][N],id_node[N],id_num[15];char str[N];void solve(){    int n;    rd(n);    scanf("%s",str);    for(int i=0;i<10;++i){        rd(a[i]);rd(b[i]);    }    for(int i=0;i<n;++i)        for(int j=0;j<n;++j)            rd(w[i][j]);    tot_edge=0;    src=0;    head[0]=-1;    sink=0;    for(int i=0;i<n;++i)        for(int j=i+1;j<n;++j){            id_edge[i][j]=++sink;            head[sink]=-1;        }    for(int i=0;i<n;++i){        str[i]-='0';        id_node[i]=++sink;        head[sink]=-1;    }    for(int i=0;i<10;++i){        id_num[i]=++sink;        head[sink]=-1;    }    ++sink;    head[sink]=-1;    int tot=0;    for(int i=0;i<n;++i)        for(int j=i+1;j<n;++j){            tot+=w[i][j]+w[j][i];            add_edge(src,id_edge[i][j],w[i][j]+w[j][i]);            add_edge(id_edge[i][j],id_node[i],inf);            add_edge(id_edge[i][j],id_node[j],inf);        }    for(int i=0;i<n;++i){        add_edge(id_node[i],id_num[str[i]],inf);        add_edge(id_node[i],sink,a[str[i]]);    }    for(int i=0;i<10;++i)        add_edge(id_num[i],sink,b[i]-a[i]);    printf("%d\n",tot-Dinic());}int main(){    int cas,kase=0;    for(rd(cas);cas--;){        printf("Case #%d: ",++kase);        solve();    }    return 0;}
0 0
原创粉丝点击