CF132E Bits of merry old England

eee_hoho

2021-03-30 21:55:50

Solution

考虑网络流建图,一个变量可以保留至下一次被询问当且仅当 $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** ``` cpp #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; } ```