Codeforces 863F - Almost Permutation
863F - Almost Permutation
题意
给出每个位置可以放的数字的范围,定义 \(cost = \sum_{i=1}^{n}(cnt(i))^2\) ,其中 \(cnt(i)\) 为数字 \(i\) \((1 \leq i \leq n)\) 出现的次数。将每个位置都填上一个数字,求 \(cost\) 的最小值。
分析
没想到可以用网络流去解决这道问题。本题属于最小费用最大流问题。
对于每个代表数字的结点,从源点都要连 \(n\) 条边,费用为\(1,\ 3,\ 5,...,\ 2*k-1\),前缀和正好对应某个数字取 \(k\) 次时的花费。根据位置和可以放的数字之间的对应关系连边,费用为 \(0\) ,所有代表位置的结点连边到汇点,费用为 \(0\)。以上每条边的容量都为 \(1\) 。跑一下费用流的模板即可。
思维好题啊。
code
#include<bits/stdc++.h>
#define l first
#define r second
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int MAXN = 1005; //
const int MAXM = 10005; // 注意扩张的边的数量
const int INF = 0x3f3f3f3f;
struct Edge {
int to, next, cap, flow, cost;
} edge[MAXM * 4];
int head[MAXN], tol;
int pre[MAXN], dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n) {
N = n;
tol = 0;
memset(head, -1, sizeof head);
memset(pre, 0, sizeof pre);
memset(dis, 0, sizeof dis);
memset(vis, 0, sizeof vis);
memset(edge, 0, sizeof edge);
}
void addedge (int u, int v, int cap, int cost) {
edge[tol] = Edge{v, head[u], cap, 0, cost};
head[u] = tol++;
edge[tol] = Edge{u, head[v], 0, 0, -cost};
head[v] = tol++;
}
bool spfa(int s, int t) {
queue<int>q;
for(int i = 0; i < N; i++) {
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i]. to;
if(edge[i].cap > edge[i].flow &&
dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t] == -1) return false;
else return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s, int t, int &cost) {
int flow = 0;
cost = 0;
while(spfa(s,t)) {
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
if(Min > edge[i].cap - edge[i]. flow)
Min = edge[i].cap - edge[i].flow;
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}
P a[110];
int main() {
int n, q;
cin >> n >> q;
for(int i = 1; i <= n; i++) {
a[i].l = 1;
a[i].r = n;
}
int flg = 0;
while(q--) {
int op, l, r, v;
cin >> op >> l >> r >> v;
for(int i = l; i <= r; i++) {
if(op == 1) {
a[i].l = max(a[i].l, v);
} else {
a[i].r = min(a[i].r, v);
}
if(a[i].l > a[i].r) {
flg = 1;
break;
}
}
}
init(2 * n + 2);
int s = 0, t = 2 * n + 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) { // 源点向每个代表数字的结点连 n 条边
addedge(s, i, 1, 1 + 2 * (j - 1));
}
for(int j = a[i].l; j <= a[i].r; j++) { // 根据数字和位置的对应关系连边
addedge(j, i + n, 1, 0);
}
addedge(i + n, t, 1, 0); // 代表位置的结点向汇点连边
}
int cost = 0;
int flow = minCostMaxflow(s, t, cost);
if(flow != n) cost = -1;
cout << cost << endl;
}
Codeforces 863F - Almost Permutation的更多相关文章
- [Codeforces 1208D]Restore Permutation (树状数组)
[Codeforces 1208D]Restore Permutation (树状数组) 题面 有一个长度为n的排列a.对于每个元素i,\(s_i\)表示\(\sum_{j=1,a_j<a_i} ...
- CodeForces 483C Diverse Permutation
Diverse Permutation Time Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64 ...
- codeforces 483C.Diverse Permutation 解题报告
题目链接:http://codeforces.com/problemset/problem/483/C 题目意思:给出 n 和 k,要求输出一个含有 n 个数的排列 p1, p2, ...,pn,使得 ...
- Codeforces 285C - Building Permutation
285C - Building Permutation 思路:贪心.因为每个数都不同且不超过n,而且长度也为n,所有排列只能为1 2 3 ......n.所以排好序后与对应元素的差值的绝对值加起来就是 ...
- codeforces C. Diverse Permutation
C. Diverse Permutation time limit per test 1 second memory limit per test 256 megabytes input standa ...
- CodeForces - 233A Perfect Permutation
A. Perfect Permutation time limit per test: 2 seconds memory limit per test: 256 megabytes input: st ...
- Codeforces 932.C Permutation Cycle
C. Permutation Cycle time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces 932 C.Permutation Cycle-数学 (ICM Technex 2018 and Codeforces Round #463 (Div. 1 + Div. 2, combined))
C. Permutation Cycle time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- [Codeforces 482A] Diverse Permutation
[题目链接] https://codeforces.com/contest/482/problem/A [算法] 首先构造一个(k + 1)个数的序列 , 满足它们的差为1-k 对于i > k ...
随机推荐
- 2017博普杯 东北大学邀请赛(B. Drink too much water)(贪心+树链剖分)
题目地址:https://oj.neu.edu.cn/problem/1204 题目大意: 其实就是树上的线段覆盖, 给出一棵n个结点的树,然后给出树上的一些路径进行覆盖,然后要求选取最少的点,能够把 ...
- JavaScript十大经典排序算法
排序算法说明 (1)排序的定义:对一序列对象根据某个关键字进行排序: 输入:n个数:a1,a2,a3,…,an输出:n个数的排列:a1’,a2’,a3’,…,an’,使得a1’ 再讲的形象点就是排排坐 ...
- taotao用户注册前台页面
注册页面效果: 注册jsp: <%@ page language="java" contentType="text/html; charset=UTF-8" ...
- 利用WebStorm来管理你的Github
什么是Github Github是一个共享虚拟主机服务,用于存放使用Git版本控制的软件代码和内容项目,以最简单的方式来说,其实就是一个代码库,上面有全世界无数优秀的码农上传自己的作品和大家共享(当然 ...
- Matlab xpC启动盘
要点: 1.target PC的网卡支持类型有限: 2.网上所列教程未必适用于本地,仅以两图表示: a,带有图形界面时容易出错: b,启动选项为Removable Device:
- 【HDU5785】Interesting [Manacher]
Interesting Time Limit: 30 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description Input Outp ...
- 用 C# 代码如何实现让你的电脑关机,重启,注销,锁定,休眠,睡眠
简介 本文讲述了用 C# 代码如何实现让你的电脑关机,重启,注销,锁定,休眠,睡眠. 如何实现 首先,使用 using 语句添加我们需要的命名空间: using System.Diagnostics; ...
- [Leetcode Week5]Word Ladder II
Word Ladder II 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder-ii/description/ Descripti ...
- appium===Python+Appium环境部署教程
*前提是你已经安装好python,以及python的pip工具 *安装python请自行百度教程~ 1.安装安卓sdk 安装包:http://tools.android-studio.org/inde ...
- Google Breakpad: 实战crash .
Google Breakpad: 实战crash . http://blog.csdn.net/zm_21/article/details/24795205 C/C++程序最棘手的时候就是一个字“挂” ...