• 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)\) 转移。傻逼出题人还要求输出方案,我就觉得离谱。

    写不出来。

    感染

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

  • 相关阅读:
    Leetcode 204. Count Primes
    Leetcode 263. Ugly Number
    Leetcode 202. Happy Number
    Leetcode 258. Add Digits
    Leetcode 23. Merge k Sorted Lists
    BAT 批处理脚本教程
    入门训练 序列求和
    JAVA学习:方法
    大小之差
    java中length,length(),size()区别
  • 原文地址:https://www.cnblogs.com/amagaisite/p/15879140.html
Copyright © 2020-2023  润新知