zoukankan      html  css  js  c++  java
  • CF132E Bits of merry old England

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

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

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

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

    (1le nle250) , (1le mle26)


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

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

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

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

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

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

    (x_i o 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
    ",'a' + ans[i].x - 1,ans[i].y);
    		else
    			printf("print(%c)
    ",'a' + ans[i].x - 1);
    	return 0;
    }
    
  • 相关阅读:
    PL/SQL database character set(AL32UTF8) and Client character set(ZHS16GBK) are different
    pl sql 无法解析指定的连接标识符
    【转】几个常用的Oracle存储过程
    .NET 条件查询实现--类似网上商城宝贝搜索
    SQL Server 中大小写区分的处理
    .NET DataGrid 导出Excel 无分页
    C# 读书笔记之访问虚方法、重写方法和隐藏方法
    人工智能技术在中小学课堂中的应用
    dzzoffice协同办公平台与onlyoffice在线协作平台安装与部署
    一本通 确定进制
  • 原文地址:https://www.cnblogs.com/sdlang/p/14599104.html
Copyright © 2011-2022 走看看