noi2015解题报告

10 篇文章 0 订阅
4 篇文章 0 订阅

D1T1:

斯波离散化+并查集题不解释。

#include <bits/stdc++.h>
#define ll long long
#define gc getchar()
#define pb push_back
#define N 100009
using namespace std;
ll n,c[N],father[N];
ll a[N],b[N];
vector<ll> p;
ll getfather(ll x)
{
	return father[x]==x?x:father[x]=getfather(father[x]);
}
ll read()
{
	ll x;
	scanf("%lld",&x);
	return x;
}
int main()
{
	ll T=read();
	while (T--)
	{
		bool flag=1;
		n=read(),p.clear();
		for (ll i=1;i<=n;i++)
		{
			a[i]=read(),b[i]=read(),c[i]=read();
			p.pb(a[i]),p.pb(b[i]);
		}
		sort(p.begin(),p.end());
		p.erase(unique(p.begin(),p.end()),p.end());
		for (ll i=1;i<=p.size();i++) father[i]=i;
		for (ll i=1;i<=n;i++)
		{
			a[i]=lower_bound(p.begin(),p.end(),a[i])-p.begin()+1;
			b[i]=lower_bound(p.begin(),p.end(),b[i])-p.begin()+1;
			if (c[i])
			{
				ll x=getfather(a[i]),y=getfather(b[i]);
				if (x!=y) father[x]=y;
			}
		}
		for (ll i=1;i<=p.size();i++) father[i]=getfather(i);
		for (ll i=1;i<=n;i++)
			if (!c[i]&&father[a[i]]==father[b[i]])
			{
				flag=0;
				break;
			}
		puts(flag?"YES":"NO");
	}
	return 0;
}
D2T2

认真(sui bian)撕烤后,发现可以树链剖分。然后就是一道模板题。(一遍ce一遍A)

#include <bits/stdc++.h>
#define ll long long
#define gc getchar()
#define pb push_back
#define N 100009
#define root 1,1,n
#define NOW int cur,int l,int r
#define mid (l+r>>1)
#define lc cur<<1
#define rc lc|1
#define lson lc,l,mid
#define rson rc,mid+1,r
#define now cur,l,r
using namespace std;
int n,m,a[N],first[N],number,x,father[N],top[N],size[N],Mson[N];
int dfn[N],deep[N],ed[N],cnt,sum[N<<2],tg[N<<2];
struct edge
{
	int to,next;
	void add(int x,int y)
	{
		to=y,next=first[x],first[x]=number;
	}
}e[N];
int read()
{
	int x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	int s=ch-'0';
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
	return s*x;
}
void Dfs(int x,int y)
{
	top[x]=y;
	dfn[x]=++cnt;
	if (Mson[x]) Dfs(Mson[x],y);
	for (int i=first[x];i;i=e[i].next)
		if (e[i].to!=Mson[x]) Dfs(e[i].to,e[i].to);
	ed[x]=cnt;
}
void dfs(int x,int fa)
{
	size[x]=1;
	father[x]=fa;
	deep[x]=deep[fa]+1;
	for (int i=first[x];i;i=e[i].next)
	{
		dfs(e[i].to,x);
		size[x]+=size[e[i].to];
		if (size[e[i].to]>size[Mson[x]]) Mson[x]=e[i].to;
	}
}
void up(NOW)
{
	sum[cur]=sum[lc]+sum[rc];
}
void down(NOW)
{
	if (tg[cur])
	{
		sum[lc]=(mid-l+1)*(tg[cur]-1);
		tg[lc]=tg[cur];
		sum[rc]=(r-mid)*(tg[cur]-1);
		tg[rc]=tg[cur];
		tg[cur]=0;
	}
}
void ins(NOW,int L,int R,int x)
{
	if (L<=l&&R>=r)
	{
		tg[cur]=x+1;
		sum[cur]=x*(r-l+1);
		return;
	}
	down(now);
	if (L<=mid) ins(lson,L,R,x);
	if (R>mid) ins(rson,L,R,x);
	up(now);
}
void Ins(int x)
{
	for (;top[x]!=0;x=father[top[x]])
		ins(root,dfn[top[x]],dfn[x],1);
	ins(root,dfn[1],dfn[x],1);
}
int qry(NOW,int L,int R)
{
	if (L<=l&&R>=r) return sum[cur];
	down(now);
	int ans=0;
	if (L<=mid) ans+=qry(lson,L,R);
	if (R>mid) ans+=qry(rson,L,R);
	up(now);
	return ans;
}
int qry(int x)
{
	int ans=0;
	for (;top[x]!=0;x=father[top[x]])
		ans+=qry(root,dfn[top[x]],dfn[x]);
	ans+=qry(root,dfn[1],dfn[x]);
	return ans;
}
int main()
{
	n=read();
	for (int i=2;i<=n;i++) e[++number].add(x=read()+1,i);
	dfs(1,0);
	Dfs(1,0);
	m=read();
	for (int i=1;i<=m;i++)
	{
		char ch;
		while (ch=gc,ch!='i'&&ch!='u');
		x=read()+1;
		if (ch=='i')
		{
			printf("%d\n",deep[x]-qry(x));
			Ins(x);
		}
		else
		{
			printf("%d\n",qry(root,dfn[x],ed[x]));
			ins(root,dfn[x],ed[x],0);
		}
	}
	return 0;
}

D1T3:

首先小于根号500的素数只有8个,状压记录两个人各选了其中的哪几个。然后分解后有大质数的可以按大质数分类(没大质数的每个自成一类),这样显然可以一一对应,每类显然都只能一个人选,然后dp转移一下。

g[0][i][j]表示当前第一个人选择,第一个人选了集合为i的素数,第二个选了j的方案数。g[1][i][j]同理。

然后f[i][j]表示第一个人选了集合为i的素数,第二个选了j的方案数的总方案数。注意每次减掉两个人这轮都没有选的情况,就是减掉原来的f[i][j]。然后累加就好了。。

#include <bits/stdc++.h>
#define gc getchar()
#define N 509
using namespace std;
const int pri[8]={2,3,5,7,11,13,17,19};
pair<int,int> p[N];
int n,mod,f[1<<8][1<<8],g[2][1<<8][1<<8];
int read()
{
	int x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	int s=ch-'0';
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
	return s*x;
}
int main()
{
	n=read(),mod=read();
	for (int i=2;i<=n;i++)
	{
		int now=i;
		for (int j=0;j<8;j++)
			if (i%pri[j]==0)
			{
				p[i].second|=1<<j;
				while (now%pri[j]==0) now/=pri[j];
			}
		p[i].first=now;
	}
	sort(p+2,p+n+1);
	f[0][0]=1;
	for (int i=2;i<=n;i++)
	{
		if (p[i].first!=p[i-1].first||p[i].first==1)
		{
			memcpy(g[0],f,sizeof(g[0]));
			memcpy(g[1],f,sizeof(g[1]));
		}
		for (int j=(1<<8)-1;j>=0;j--)
			for (int k=(1<<8)-1;k>=0;k--)
			{
				if ((j&p[i].second)==0)
					g[1][j][k|p[i].second]=(g[1][j][k|p[i].second]+g[1][j][k])%mod;
				if ((k&p[i].second)==0)
					g[0][j|p[i].second][k]=(g[0][j|p[i].second][k]+g[0][j][k])%mod;
			}	
		if (p[i].first!=p[i+1].first||p[i].first==1)	
			for (int j=0;j<(1<<8);j++)
				for (int k=0;k<(1<<8);k++)
					f[j][k]=((g[0][j][k]+g[1][j][k])%mod-f[j][k]+mod)%mod;
	}
	int ans=0;
	for (int i=0;i<(1<<8);i++)
		for (int j=0;j<(1<<8);j++)
			if ((i&j)==0) ans=(ans+f[i][j])%mod;
	printf("%d\n",ans);
	return 0;
}

D2T1:

其实就是一个k叉哈夫曼树,每次都挑选其中最小的k个合并为一个再加进去,然后发现这样(n-1)%(k-1)!=0就很尴尬,然而其实很简单,加上几个(搞笑的)节点权值为零就好。

然后考虑如何让深度最小,其实也就是当权值相同时挑选深度较小的合并就好啦。优先队列<号重载就好啦。

#include <bits/stdc++.h>
#define gc getchar()
#define N 100009
#define ll long long
using namespace std;
ll n,k,w[N],cnt,Ans;
struct node
{
	ll val,deep;
	node(ll val=0,ll deep=0):val(val),deep(deep){}
};
bool operator <(const node &x,const node &y)
{
	return x.val>y.val||(x.val==y.val&&x.deep>y.deep);
}
priority_queue<node> p;
ll read()
{
	ll x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	ll s=ch-'0';
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
	return s*x;
}
int main()
{
	n=read(),k=read();
	for (ll i=1;i<=n;i++) w[i]=read(),p.push(node(w[i],1)),++cnt;
	if ((n-1)%(k-1)!=0)
		for (ll i=1;i<=k-1-(n-1)%(k-1);i++)
			p.push(node(0,1)),++cnt;
	while (cnt>1)
	{
		ll sum=0,Max_deep=0;
		for (ll i=1;i<=k;i++)
		{
			sum+=p.top().val;
			Max_deep=max(Max_deep,p.top().deep);
			p.pop();
		}
		Ans+=sum;
		p.push(node(sum,Max_deep+1));
		cnt-=k-1;
	}
	printf("%lld\n%lld\n",Ans,p.top().deep-1);
	return 0;
}

D2T2:

发现就是求后缀中lcp>=l的对数和最大的权值积。

lcp可以想到后缀数组中height数组取最小值就好了。

从大到小加入,每次合并两边的区间,维护答案,然后对于对数差分一下,最大权值积只要每个区间维护最大最小值(因为有负的!!)就好啦。

#include <bits/stdc++.h>
#define gc getchar()
#define N 300009
#define ll long long
using namespace std;
ll n,f[N],a[N],pos[N],fa[N],Ans[N],sum[N];
struct node
{
	ll number,Max,Min,pre,next;
	node(ll number=0,ll Max=0,ll Min=0,ll pre=0,ll next=0):number(number),Max(Max),Min(Min),pre(pre),next(next){}
}p[N];
ll read()
{
	ll x=1;
	char ch;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	ll s=ch-'0';
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
	return s*x;
}
ll sa[N],Rank[N],height[N];
ll wa[N],wb[N],wv[N],wd[N];
bool cmp(ll *r,ll a,ll b,ll l)  
{
    return r[a]==r[b]&&r[a+l]==r[b+l];  
}
void da(ll *r,ll n,ll m)  
{
    ll *x=wa,*y=wb,*t;  
    for (ll i=0;i<m;i++) wd[i]=0;  
    for (ll i=0;i<n;i++) wd[x[i]=r[i]]++;  
    for (ll i=1;i<m;i++) wd[i]+=wd[i-1];  
    for (ll i=n-1;i>=0;i--) sa[--wd[x[i]]]=i;  
    for (ll j=1,p=1,i;p<n;j<<=1,m=p)  
    {
        for (p=0,i=n-j;i<n;i++) y[p++]=i;  
        for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;  
        for (i=0;i<n;i++) wv[i]=x[y[i]];  
        for (i=0;i<m;i++) wd[i]=0;  
        for (i=0;i<n;i++) wd[wv[i]]++;  
        for (i=1;i<m;i++) wd[i]+=wd[i-1];  
        for (i=n-1;i>=0;i--) sa[--wd[wv[i]]]=y[i];  
        for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
			x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;  
    }
}
void get_height(ll *r,ll n)  
{
    for (ll i=1;i<=n;i++) Rank[sa[i]]=i;
    for (ll i=0,k=0,j;i<n;height[Rank[i++]]=k)  
        for (k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);  
}
bool cm(ll x,ll y)
{
	return height[x]>height[y];
}
ll getfa(ll x)
{
	return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
int main()
{
	freopen("savour9.in","r",stdin);
	freopen("savour.out","w",stdout);
	n=read();
	for (ll i=0;i<n;i++)
	{
		char ch;
		while (ch=gc,ch<'a'||ch>'z');
		a[i]=ch-'a'+1;
	}
	a[n]=0;
	da(a,n+1,27);
	for (ll i=0;i<n;i++)
		pos[i+1]=i+1,f[i]=read(),sum[i]=-9223372036854775800ll;
	sum[n]=sum[n-1];
	get_height(a,n);
	sort(pos+1,pos+n+1,cm);
	ll now=1;
	p[0].next=1;
	for (ll i=1;i<=n;i++)
		p[i]=node(1,f[sa[i]],f[sa[i]],i-1,i+1),fa[i]=i;
	p[n+1].pre=n;
	for (ll i=n-1;i>=0;i--)
	{
		while (height[pos[now]]>=i&&now<=n)
		{
			if (pos[now]<=1)
			{
				now++;
				continue;
			}
			node tmp;
			ll x=getfa(pos[now]),y=getfa(pos[now]-1);
			Ans[i]+=p[x].number*p[y].number;
			sum[i]=max(sum[i],p[x].Max*p[y].Max);
			sum[i]=max(sum[i],p[x].Max*p[y].Min);
			sum[i]=max(sum[i],p[x].Min*p[y].Max);
			sum[i]=max(sum[i],p[x].Min*p[y].Min);
			tmp.number=p[x].number+p[y].number;
			tmp.Max=max(p[x].Max,p[y].Max);
			tmp.Min=min(p[x].Min,p[y].Min);
			tmp.pre=p[y].pre;
			tmp.next=p[x].next;
			p[p[y].pre].next=x;
			p[x]=tmp;
			fa[y]=x;
			now++;
		}
	}
	for (ll i=n-1;i>=0;i--)
		Ans[i]+=Ans[i+1],sum[i]=max(sum[i],sum[i+1]);
	for (ll i=0;i<n;i++)
		printf("%lld %lld\n",Ans[i],Ans[i]==0?0:sum[i]);
	return 0;
}
D2T3:

首先对于每个点 根据x,x+y,x-y的值可以分类,每种离散化一下,

类相同的之间可以连边,当然x相同的也行。(写完突然消失了不开心,就只好简单讲了。。。)

第一问:

dp出通过向上的三种方式到达的最大值(用前缀,后缀最大值优化一下),然后统计答案。

第二问:

第一问dp时用pre数组记录上一个走的点,然后倒推回去就好了(注意同一行左右的前后顺序)

第三问:

把两个通过第一题三种转移方法到达的,且答案等于第一问的 点对连边(下界:1,上界:inf)

源点汇点跟每个点连下边,因为肯定可行,所以直接跑最大流,然后sum-最大流就是答案啦(最小流)

#include <bits/stdc++.h>
#define gc getchar()
#define N 50009
#define inf 2147483647
using namespace std;
int n,f[N],beg[N],ed[N],s[3][N],pre[3][N],cnt,pl[N];
int Maxl[N],Maxlnum[N],Maxr[N],Maxrnum[N];
int S,T,SS,TT,pd[N],pdl[N],pdr[N],du[N],dn[N],sum;
struct node
{
	int x,y,lei[3],num;
}p[N];
vector<int> link[3],Y;
bool operator <(const node &a,const node &b)
{
	return a.y<b.y||(a.y==b.y&&a.x<b.x);
}
struct edge
{
	int from,to,cap,flow;
	edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
vector<edge> e;
vector<int> G[N];
int d[N],cur[N];
bool vis[N];
int read()
{
	char ch;
	int x=1;
	while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
	int s=ch-'0';
	while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';
	return s*x;
}
void add(int from,int to,int cap)
{
	e.push_back(edge(from,to,cap,0));
	e.push_back(edge(to,from,0,0));
	int m=e.size();
	G[from].push_back(m-2);
	G[to].push_back(m-1);
}
#define E e[G[x][i]]
bool bfs(int s,int t)
{
	memset(vis,0,sizeof(vis));
	queue<int> Q;
	Q.push(s);
	d[s]=0;
	vis[s]=1;
	while (!Q.empty())
	{
		int x=Q.front();
		Q.pop();
		for (int i=0;i<G[x].size();i++)
			if (!vis[E.to]&&E.cap>E.flow)
			{
				vis[E.to]=1;
				d[E.to]=d[x]+1;
				Q.push(E.to);
			}
	}
	return vis[t];
}
int dfs(int x,int a,int s,int t)
{
	if (x==t||a==0) return a;
	int flow=0,f;
	for (int &i=cur[x];i<G[x].size();i++)
		if (d[x]+1==d[E.to]&&(f=dfs(E.to,min(a,E.cap-E.flow),s,t))>0)
		{
			E.flow+=f;
			e[G[x][i]^1].flow-=f;
			flow+=f;
			a-=f;
			if (!a) break;
		}
	return flow;
}
int Maxflow(int s,int t)
{
	int flow=0;
	while (bfs(s,t))
	{
		memset(cur,0,sizeof(cur));
		flow+=dfs(s,inf,s,t);
	}
	return flow;
}
#undef E
void Add(int x,int y,int Min,int Max)
{
	du[x]-=Min,du[y]+=Min;
	add(x,y,Max-Min);
}
int main()
{
	n=read();
	for (int i=1;i<=n;i++)
	{
		p[i].x=read(),p[i].y=read();
		p[i].lei[0]=p[i].x-p[i].y;
		p[i].lei[1]=p[i].x;
		p[i].lei[2]=p[i].x+p[i].y;
		p[i].num=i;
		link[0].push_back(p[i].lei[0]);
		link[1].push_back(p[i].lei[1]);
		link[2].push_back(p[i].lei[2]);
		Y.push_back(p[i].y);
	}
	n++;
	sort(p+1,p+n+1);
	for (int i=0;i<3;i++)
	{
		link[i].push_back(0);
		sort(link[i].begin(),link[i].end());
		link[i].erase(unique(link[i].begin(),link[i].end()),link[i].end());
	}
	Y.push_back(0);
	sort(Y.begin(),Y.end());
	Y.erase(unique(Y.begin(),Y.end()),Y.end());
	for (int i=1;i<=n;i++)
	{
		for (int j=0;j<3;j++)
			p[i].lei[j]=lower_bound(link[j].begin(),link[j].end(),p[i].lei[j])-link[j].begin()+1;
		p[i].y=lower_bound(Y.begin(),Y.end(),p[i].y)-Y.begin()+1;
		if (!beg[p[i].y]) beg[p[i].y]=i;
		ed[p[i].y]=i;
	}
	for (int i=2;i<=n;i++) f[i]=-1;
	for (int i=0;i<3;i++)
		s[i][lower_bound(link[i].begin(),link[i].end(),0)-link[i].begin()+1]=1;
	Maxl[1]=-1,Maxlnum[1]=1,Maxr[1]=1,Maxrnum[1]=1;
	for (int i=2;i<=(int)Y.size();i++)
	{
		for (int j=beg[i];j<=ed[i];j++)
			for (int k=0;k<3;k++)
			{
				if (s[k][p[j].lei[k]]>0)
				{
					int u=s[k][p[j].lei[k]];
					pre[k][j]=u;
					if (f[u]!=-1) f[j]=max(f[j],f[u]+1);
					if (u!=beg[p[u].y]&&Maxlnum[u-1]>0)
						f[j]=max(f[j],Maxl[u-1]+u-beg[p[u].y]+1);
					if (u!=ed[p[u].y]&&Maxrnum[u+1]>0)
						f[j]=max(f[j],Maxr[u+1]+ed[p[u].y]-u+1);
				}
				s[k][p[j].lei[k]]=j;
			}
		if (f[beg[i]]>0)
		{
			Maxl[beg[i]]=f[beg[i]];
			Maxlnum[beg[i]]=beg[i];
		}
		for (int j=beg[i]+1;j<=ed[i];j++)
		{
			Maxl[j]=Maxl[j-1],Maxlnum[j]=Maxlnum[j-1];
			if ((f[j]>=Maxl[j]||Maxlnum[j]==0)&&f[j]>0)
			{
				Maxl[j]=f[j];
				Maxlnum[j]=j;
			}
		}
		if (f[ed[i]]>0)
		{
			Maxr[ed[i]]=f[ed[i]];
			Maxrnum[ed[i]]=ed[i];
		}
		for (int j=ed[i]-1;j>=beg[i];j--)
		{
			Maxr[j]=Maxr[j+1],Maxrnum[j]=Maxrnum[j+1];
			if ((f[j]>=Maxr[j]||Maxrnum[j]==0)&&f[j]>0)
			{
				Maxr[j]=f[j];
				Maxrnum[j]=j;
			}
		}
	}
	int ans=0,now=1;
	for (int i=2;i<=n;i++)
		if (f[i]+ed[p[i].y]-beg[p[i].y]>ans)
		{
			ans=f[i]+ed[p[i].y]-beg[p[i].y];
			now=i;
		}
	printf("%d\n",ans);//Max trees 
	for (int i=ed[p[now].y];i>now;i--) pl[++cnt]=p[i].num;
	for (int i=beg[p[now].y];i<now;i++) pl[++cnt]=p[i].num;
	while (now!=1)
	{
		pl[++cnt]=p[now].num;
		for (int k=0;k<3;k++)
		{
			int u=pre[k][now];
			if (u>0)
			{
				if (f[u]+1==f[now])
				{
					now=u;
					break;
				}
				if (u!=beg[p[u].y]&&Maxl[u-1]+u-beg[p[u].y]+1==f[now]&&Maxlnum[u-1]>0)
				{
					for (int i=u;i>Maxlnum[u-1];i--) pl[++cnt]=p[i].num;
					for (int i=beg[p[u].y];i<Maxlnum[u-1];i++) pl[++cnt]=p[i].num;
					now=Maxlnum[u-1];
					break;
				}
				if (u!=ed[p[u].y]&&Maxr[u+1]+ed[p[u].y]-u+1==f[now]&&Maxrnum[u+1]>0)
				{
					for (int i=u;i<Maxrnum[u+1];i++) pl[++cnt]=p[i].num;
					for (int i=ed[p[u].y];i>Maxrnum[u+1];i--) pl[++cnt]=p[i].num;
					now=Maxrnum[u+1];
					break;
				}
			}
		}
	}
	for (int i=cnt;i>=1;i--)
		printf("%d%s",pl[i],i==1?"\n":" ");//print out plans 
	for (int i=2;i<=n;i++)
		if (f[i]+ed[p[i].y]-beg[p[i].y]==ans) pd[i]=1;
	S=n+1,T=n+2,SS=n+3,TT=n+4;
	for (int i=(int)Y.size();i;i--)
	{
		int bjm=n+1;
		for (int j=ed[i];j>=beg[i];j--)
		{
			if (pdl[j]) bjm=Maxl[j];
			if (bjm==f[j]) pd[j]=1;
		}
		bjm=n+1;
		for (int j=beg[i];j<=ed[i];j++)
		{
			if (pdr[j]) bjm=Maxr[j];
			if (bjm==f[j]) pd[j]=1;
		}
		for (int j=beg[i];j<=ed[i];j++)
		{
			if (!pd[j]) continue;
			for (int k=0;k<3;k++)
			{
				int u=pre[k][j];
				if (!u) continue;
				bool flag=0;
				if (f[u]+1==f[j])
				{
					pd[u]=1;
					flag=1;
				}
				if (u!=beg[p[u].y]&&Maxl[u-1]+u-beg[p[u].y]+1==f[j]&&Maxlnum[u-1]>0)
				{
					pdl[u-1]=1;
					flag=1;
				}
				if (u!=ed[p[u].y]&&Maxr[u+1]+ed[p[u].y]-u+1==f[j]&&Maxrnum[u+1]>0)
				{
					pdr[u+1]=1;
					flag=1;
				}
				if (flag) Add(u,j,1,inf);//u is past
			}
		}
	}
	for (int i=1;i<=n;i++)
	{
		add(S,i,inf);
		add(i,T,inf);
		if (du[i]>0) add(SS,i,du[i]),sum+=du[i];
		else if (du[i]<0) add(i,TT,-du[i]);
	}
	int flow=Maxflow(SS,TT);
	printf("%d\n",sum-flow);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值