CF132E Bits of merry old England

有一个长度为 \(n\) 的序列 \(a\) ,有 \(m\) 个变量,要求给出操作序列,来输出这 \(n\) 个数,你能进行两种操作:

  1. 对某个变量赋值。
  2. 输出某个变量。

变量没有初值,每次赋值的代价是你赋的值得二进制表示中 \(1\) 的个数。

要求给出一个操作序列最小化代价,并输出方案。

\(1\le n\le250\) , \(1\le m\le26\)


考虑网络流建图,一个变量可以保留至下一次被询问当且仅当 \(l,r\) 这段时间都保留下来,这个不好限制,那么我们可以看作每次都要加代价,然后 \(r-1\) 天又减去代价,这样就可以看作保留下来了。

那么考虑建图,每个点拆成两个点 \(x_i,y_i\)

\(S\to x_i\) 流量为 \(1\) ,费用为 \(a_i\) 的代价,代表每次都要赋值。

\(x_i\to y_i\) ,流量为 \(1\) ,费用为 \(0\) ,代表不减去代价。

\(y_i\to T\) ,流量为 \(1\) ,费用为 \(0\) ,代表减去代价或以后被覆盖这两个操作只能进行一次。

\(x_{i-1}\) 向上一个 \(a_j=a_i\)\(y_j\) 连边,流量为 \(1\) ,费用为 \(-a_i\)的代价,代表上一次保留到现在要减去代价。

\(x_i\to x_{i+1}\) ,流量为 \(m-1\) ,费用为 \(0\) ,代表这次的变量保留到下次,因为下次还要赋值,所以是 \(m-1\)

然后方案的话记录下每个 \(a_i\) 被保留到了什么时候,模拟一下就可以了。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#define fi first
#define se second
const int N = 250;
using namespace std;
int n,k,a[N + 5],x[N + 5],y[N + 5],S,T,idc,ans1,ans2,sl[N + 5],ID[N * 3 + 5],t[N + 5],num[N + 5],tt[N + 5];
struct node
{
	int x,y,opt;
};
vector <node> ans;
namespace F
{
	const int N = 3e6;
	const long long inf = 2e18;
	#define mp make_pair
	struct edges
	{
		int v;
		long long w,f;
	}edge[N + 5];
	int head[N + 5],S,T,nxt[N + 5],edge_cnt = 1,cur[N + 5],vis[N + 5],p[N + 5],q[N + 5];
	long long dis[N + 5],cost;
	void add_edge(int u,int v,long long w,long long f)
	{
		edge[++edge_cnt] = (edges){v,w,f};
		nxt[edge_cnt] = head[u];
		head[u] = edge_cnt;
	}
	void add(int u,int v,long long w,long long f)
	{
		add_edge(u,v,w,f);
		add_edge(v,u,0,-f);
	}
	bool spfa()
	{
		for (int i = 1;i <= idc;i++)
			dis[i] = inf,cur[i] = head[i],vis[i] = p[i] = 0;
		int l = 1,r = 0;
		dis[S] = 0;
		q[++r] = S;
		while (l <= r)
		{
			int u = q[l++];
			vis[u] = 0;
			for (int i = head[u];i;i = nxt[i])
			{
				int v = edge[i].v;
				long long w = edge[i].w,f = edge[i].f;
				if (w && dis[v] > dis[u] + f)
				{
					dis[v] = dis[u] + f;
					if (!vis[v])
					{
						q[++r] = v;
						vis[v] = 1;
					}
				}
			}
		}
		return dis[T] != inf;
	}
	long long dfs(int u,long long flow)
	{
		if (u == T)
			return flow;
		long long sm = 0;
		p[u] = 1;
		for (int &i = cur[u];i;i = nxt[i])
		{
			int v = edge[i].v;
			long long w = edge[i].w,f = edge[i].f;
			if (w && dis[v] == dis[u] + f && !p[v])
			{
				long long res = dfs(v,min(flow,w));
				edge[i].w -= res;
				edge[i ^ 1].w += res;
				flow -= res;
				sm += res;
				cost += res * f;
				if (!flow)
					break;
			}
		}
		p[u] = 0;
		return sm;
	}
	pair <long long,long long> dinic(int s,int t)
	{
		S = s;T = t;
		long long ans = 0;
		cost = 0;
		while (spfa())
			ans += dfs(S,inf);
		return mp(ans,cost);
	}
	void solve()
	{
		for (int i = 2;i <= n;i++)
		{
			for (int j = head[x[i - 1]];j;j = nxt[j])
			{
				int v = edge[j].v;
				long long w = edge[j].w,f = edge[j].f;
				if (!w && f < 0 && v != S)
					sl[ID[v]] = i;
			}
		}
		for (int i = 1;i <= k;i++)
			t[i] = 0;
		int cnt = 0;
		for (int i = 1;i <= n;i++)
		{
			int fl = 0;
			for (int j = 1;j <= k;j++)
				if (t[j] == a[i])
				{
					ans.push_back((node){j,0,2});
					tt[j] = i;
					fl = 1;
					break;
				}
			if (fl)
				continue;
			for (int j = 1;j <= 26;j++)
				if (sl[tt[j]] <= i)
				{
					ans.push_back((node){j,a[i],1});
					ans.push_back((node){j,0,2});
					tt[j] = i;
					t[j] = a[i];
					break;
				}
		}
	}
	void clear()
	{
		for (int i = 1;i <= idc;i++)
			head[i] = 0;
		edge_cnt = 1;
		idc = 0;
	}
}
int main()
{
	scanf("%d%d",&n,&k);
	for (int i = 1;i <= n;i++)
		scanf("%d",&a[i]);
	S = ++idc;T = ++idc;
	for (int i = 1;i <= n;i++)
		x[i] = ++idc,y[i] = ++idc,ID[idc] = i;
	for (int i = 1;i <= n;i++)
	{
		F::add(S,x[i],1,__builtin_popcount(a[i]));
		F::add(y[i],T,1,0);
		F::add(x[i],y[i],1,0);
		if (i < n)
			F::add(x[i],x[i + 1],k - 1,0);
		for (int j = i - 1;j >= 1;j--)
			if (a[j] == a[i])
			{
				F::add(x[i - 1],y[j],1,-__builtin_popcount(a[i]));
				break;
			}
	}
	ans2 = F::dinic(S,T).se;
	F::solve();
	cout<<ans.size()<<" "<<ans2<<endl;
	for (int i = 0;i < ans.size();i++)
		if (ans[i].opt == 1)
			printf("%c=%d\n",'a' + ans[i].x - 1,ans[i].y);
		else
			printf("print(%c)\n",'a' + ans[i].x - 1);
	return 0;
}
posted @ 2021-03-30 21:57  eee_hoho  阅读(51)  评论(0编辑  收藏  举报