2022/2/10 模拟赛

啥也不会……还没有题解给我……做什么啊。

反正这篇水……不如公开了。

同校的可以找我要密码。当然也可以自己猜。

一般图带权多重匹配

考场:100/100(0/100,拜 tr)

注意到不会做,那就万能网络流。

考虑到不好处理 \((i,i)\) 的贡献。注意到奇数个数不多,先假设只有偶数。我们将 \((i,j)\)\((j,i)\) 看成不同的匹配方法(\((i,i)\) 同理拆成两个),将 \(a_i\) 均分。\(S\)\(1 \sim i\)\(\dfrac{a_{1 \sim i}}{2}\)\(1 \sim i\) 连向 \(n+1 \sim 2n\)\(n+1 \sim 2n\) 连向 \(T\)。费用流量都显然,最小费用最大流即可。

但是有个奇数……注意到多出来的这个我们不知道是谁的入度或出度,全部枚举一下就好了。'

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
int cnt;
int siz[1005],nxt[100005],val[100005],cst[100005],to[100005];
inline void addEdge(int u,int v,int w,int c){++cnt,to[cnt]=v,nxt[cnt]=siz[u],val[cnt]=w,cst[cnt]=c,siz[u]=cnt;}
int n,a[55],c[55][55],K,od[15],p[15],s,t;
void build()
{
	memset(siz,0,sizeof siz);
	cnt=1;
	s=2*n+1,t=s+1;
	for(int i=1;i<=n;++i)	for(int j=1;j<=n;++j)	addEdge(i,j+n,10000,c[i][j]),addEdge(j+n,i,0,-c[i][j]);
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=K;++j)
		{
			if(i==od[j])
			{
				if(p[j])
				{
					addEdge(s,i,a[i]/2+1,0);
					addEdge(i,s,0,0);
					addEdge(i+n,t,a[i]/2,0);
					addEdge(t,i+n,0,0);
				}
				else
				{
					addEdge(s,i,a[i]/2,0);
					addEdge(i,s,0,0);
					addEdge(i+n,t,a[i]/2+1,0);
					addEdge(t,i+n,0,0);
				}
				goto spec;
			}
		}
		addEdge(s,i,a[i]/2,0);
		addEdge(i,s,0,0);
		addEdge(i+n,t,a[i]/2,0);
		addEdge(t,i+n,0,0);
		spec:;
	}
}
int ntw[1005],dis[1005];
int pre[1005],lid[1005];
bool vis[1005];
bool bfs()
{
	memset(ntw,63,sizeof ntw);
	memset(dis,63,sizeof dis);
	pre[t]=-1;
	queue<int> Q;
	Q.push(s);
	dis[s]=0;
	while(!Q.empty())
	{
		int now=Q.front();
		Q.pop();
		vis[now]=false;
		for(int i=siz[now];i;i=nxt[i])
		{
			int v=to[i];
			if(val[i] && dis[now]+cst[i]<dis[v])
			{
				dis[v]=dis[now]+cst[i];
				lid[v]=i;
				pre[v]=now;
				ntw[v]=min(ntw[now],val[i]);
				if(!vis[v])
				{
					vis[v]=true;
					Q.push(v);
				}
			}
		}
	}
	return ~pre[t];
}
int solve()
{
	int cost=0;
	while(bfs())
	{
		cost+=dis[t]*ntw[t];
		int now=t;
		while(now!=s)
		{
			val[lid[now]]-=ntw[t];
			val[lid[now]^1]+=ntw[t];
			now=pre[now];
		}
	}
	return cost;
}
int main(){
	n=read();
	for(int i=1;i<=n;++i)	K+=(a[i]=read())&1;
	for(int i=1;i<=n;++i)	for(int j=1;j<=n;++j)	c[i][j]=read();
	if(K&1)	return puts("-1")&0;
	K=0;
	for(int i=1;i<=n;++i)	if(a[i]&1)	od[++K]=i;
	for(int i=K/2+1;i<=K;++i)	p[i]=1;
	int ans=2e9;
	do
	{
		build();
		ans=min(ans,solve());
	}while(next_permutation(p+1,p+1+K));
	write(ans);
	return 0;
}

排序

考场:0/100(43/100,拜 tr)

只会 \(O(2^k n\sum m)\)。大概思路是定义 \(dp_{i,l}\) 为结点 \(i\) 中构成的序列值域在 \([l,dp_{i,l}]\) 之内(显然 \(dp_{i,l}\) 越小越好),我们只关心加进去了哪些不关心顺序可以 \(O(2^k n\sum m)\) 转移。傻逼出题人还要求输出方案,我就觉得离谱。

写不出来。

感染

不会就是不会,怎么做也不会。

posted @ 2022-02-10 14:58  SyadouHayami  阅读(44)  评论(0编辑  收藏  举报

My Castle Town.