标签:路径 bool 题目 完全 ace 否则 span pre ati
给出一个\(N*N(N≤600)\)的非负矩阵\(B=(b_{ij})\),和一个\(1*N\)的非负矩阵\(C=(c_{ij})\)。\(A=(a_{ij})\)是一个\(1*N\)的\(01\)矩阵,令矩阵\(D=(d_{ij}) (A*B-C)*A^T\),则\(D\)是一个\(1*1\)的矩阵。要求构造\(A\)矩阵最大化\(D\)矩阵的元素值,输出得到的\(D\)矩阵。
上述建图法的正确性是比较显然的。我们假设一开始全选,\(ans=\sum B\);然后考虑选点\(i\)的代价是\(C_i\)(即让\(ans-=C_i\)),不选点\(i\)的代价是\(\sum_{j可不选} B_{ij}+\sum_{j必选}B_{ji}\)。显然这种代价和即为答案。实际上,我们只要建出一个满足这些代价的图即可(因而有无数种建图方法)。
#include <cstdio>
#include <algorithm>
#define min(x,y) (x<y?x:y)
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=666,M=2*N*N,inf=0x7fffffff;
int n,S,T,x,oub[N],la[N],ans,cur[N],dis[N],GAP[N];
struct edge{int v,l,ne;}e[M];
void link(int x,int y,int z)
{
static int tot=1;
e[++tot]=(edge){y,z,la[x]}, la[x]=tot;
e[++tot]=(edge){x,0,la[y]}, la[y]=tot;
}
int flow(int x,int res)
{
if(x==T) return res;
int i,have=0;
for(i=cur[x]; i; i=e[i].ne)
if(e[i].l&&dis[x]==dis[e[i].v]+1)
{
cur[x]=i;
int now=flow(e[i].v,min(res-have,e[i].l));
e[i].l-=now, e[i^1].l+=now;
if((have+=now)==res) return have;
}
cur[x]=la[x];
if(!--GAP[dis[x]]) dis[S]=T+1;
GAP[++dis[x]]++;
return have;
}
int main()
{
scanf("%d",&n), T=n+1;
fo(i,1,n) fo(j,1,n)
{
scanf("%d",&x), oub[i]+=x, ans+=x;
if(i^j) link(i,j,x);
}
fo(i,1,n) link(S,i,oub[i]), scanf("%d",&x), link(i,T,x);
GAP[0]=T+1;
while(dis[S]<=T) ans-=flow(S,inf);
printf("%d",ans);
}
求满足条件的非空序列{p[i]}的数目,结果对一个整数\(Q(\in[1,1000000000])\)取模。
时间复杂度\(O(n^2)\)。
#include <cstdio>
#include <algorithm>
#define P(x,y) (x+=y)%=Q
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=7010;
int n,Q,f[N][2],ans;
struct dot{int x,y;}p[N];
bool cmp(const dot&a,const dot&b) {return a.x<b.x;}
int main()
{
scanf("%d%d",&n,&Q);
fo(i,1,n) scanf("%d%d",&p[i].x,&p[i].y);
sort(p+1,p+n+1,cmp);
fo(i,1,n)
{
f[i][0]=f[i][1]=1;
fd(j,i-1,1) p[j].y>p[i].y ? P(f[j][1],f[i][0]) : P(f[i][0],f[j][1]);
}
fo(i,1,n) P(ans,f[i][0]), P(ans,f[i][1]);
printf("%d",(ans-n+Q)%Q);
}
对树进行一些剪枝,使树的价值最大。剪枝的方式为:如果一个结点的孩子都是叶结点,就可以将它所有的孩子剪去。
转移时用一个单调队列优化一下。
#include <cstdio>
#define max(x,y) (x>y?x:y)
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=11e4,inf=0x3f3f3f3f;
int n,w[N],t,p,pa[N],tot,to[N],ne[N],la[N],ls[N],rs[N],f[N],top,h[N],m[N],h1[N],h2[N],ans;
void work(int x,int y)
{
h1[0]=-inf;
for(top=0; x; x=rs[x])
{
h[++top]=x;
m[top+1]=max(m[top],w[x]);
h1[top]=max(h1[top-1],f[x]);
h2[top]=f[x]-m[top];
}
h2[top+1]=-inf;
fd(i,top,1) if(h2[i]<h2[i+1]) h2[i]=h2[i+1];
for(int k=0,d=m[1]; y; y=ls[y])
{
while(k<top&&d>m[k+1]) k++;
f[y]=w[y]+max(h1[k]-d,h2[k+1]);
if(d<w[y]) d=w[y];
}
}
void dfs(int x,bool l,bool r)
{
int ly=0;
for(int i=la[x],y; y=to[i]; ly=y,i=ne[i])
{
if(ly) m[1]=w[x],work(ly,y);
dfs(y,l&&!ly,r&&rs[x]==y);
}
if(l&&f[x]<w[x]) f[x]=w[x];
if(r&&f[x]>ans) ans=f[x];
}
int main()
{
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d%d",&w[i],&t);
fo(j,1,t)
{
scanf("%d",&p);
to[++tot]=p, ne[tot]=la[i], la[pa[p]=i]=tot;
if(j==1) rs[i]=p;
if(j==t) ls[i]=p;
}
f[i]=-inf;
}
dfs(1,1,1);
printf("%d",ans);
}
标签:路径 bool 题目 完全 ace 否则 span pre ati
原文地址:https://www.cnblogs.com/Iking123/p/11347964.html