1001 数长方形

题目大意

平面内有N条平行于坐标轴的线段,且不会在端点处相交

问共形成多少个矩形

算法思路

枚举4条线段的全部组合。分别作为矩形四条边。推断是否合法

时间复杂度: O(N4)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: A.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <complex> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; typedef complex<int> Point;
#define X real()
#define Y imag() const int maxn = 25 + 5; int n;
Point s[maxn], t[maxn];
bool o[maxn]; bool inter(int i, int j)
{
if (s[j].Y >= s[i].Y || t[j].Y <= s[i].Y) return false;
return s[i].X < s[j].X && s[j].X < t[i].X;
} bool check(int d, int u, int l, int r)
{
if (!inter(d, l)) return false;
if (!inter(d, r)) return false;
if (!inter(u, l)) return false;
if (!inter(u, r)) return false;
return true;
} int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
scanf("%d", &n);
rep(i,n) {
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
s[i] = Point(x1, y1);
t[i] = Point(x2, y2);
o[i] = (x1 == x2);
}
int res = 0;
rep(d,n) if (!o[d]) rep(u,n) if (u > d && !o[u]) {
rep(l,n) if (o[l]) rep(r,n) if (r > l && o[r]) {
if (check(d, u, l, r)) ++res;
}
}
printf("Case #%d:\n", ++cas);
printf("%d\n", res);
} return 0;
}

1002 弹吉他

题目大意

给出N个和弦须要按下的弦与品。每一个和弦能够选择某种手势

序号大的手指所处的品位不能小于序号小的手指

移动某个手指的代价为曼哈顿距离,问依次弹出这N个和弦的最小代价

算法思路

DP,每一个和弦最多有4!种手势

状态f[i][S]表示S相应的手势弹奏第i个和弦后,花费的最小代价

状态转移:f[i][S] = min{f[i-1][S0] + dis(S0, S)}

当中S能够直接存在4维数组中。注意检查手势是否合法

时间复杂度: O(N×4!2)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: B.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; const int maxn = 5000 + 5; int n;
Pii p[maxn][4];
int f[maxn][4][4][4][4]; bool check(int k, int y[])
{
rep(i,4) rep(j,4) if (j > i)
if (p[k][y[i]].second > p[k][y[j]].second) return false;
return true;
} int dis(int i, int x, int y)
{
int dx = p[i][x].first - p[i+1][y].first;
int dy = p[i][x].second - p[i+1][y].second;
return abs(dx) + abs(dy);
} int solve()
{
int x[4], y[4];
memset(f, 0x3f, sizeof(f));
f[0][0][1][2][3] = 0;
rep(i,n) {
rep(j,4) x[j] = j;
do {
int t = f[i][x[0]][x[1]][x[2]][x[3]];
if (t == inf) continue;
rep(j,4) y[j] = j;
do {
if (!check(i + 1, y)) continue;
int r = t;
rep(j,4) r += dis(i, x[j], y[j]);
int &res = f[i+1][y[0]][y[1]][y[2]][y[3]];
res = min(res, r);
} while (next_permutation(y , y + 4));
} while (next_permutation(x, x + 4));
}
int res = inf;
rep(j,4) x[j] = j;
do {
res = min(res, f[n][x[0]][x[1]][x[2]][x[3]]);
} while (next_permutation(x, x + 4));
return res;
} int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
scanf("%d", &n);
rep(j,4) p[0][j] = Pii(0, j + 1);
For(i,1,n) rep(j,4)
scanf("%d%d", &p[i][j].first, &p[i][j].second);
printf("Case #%d:\n", ++cas);
printf("%d\n", solve());
} return 0;
}

1003 行路难

题目大意

给出一张有向图,边权为字符串。找出指定起点到终点,字典序最小的路径

假设不存在或长度为无穷,则输出”Tough way!”

算法思路

最短路。对于我的实现方法。须要从终点向起点松弛

因为假设从起点開始,对于某个字符串是还有一个串前缀的情况。无法确定保留哪个

为了避免负环对spfa队列的影响,这里使用bellman-ford算法

  • 当起点在n-1次松弛后被更新,则答案无限长
  • 松弛6n次后起点答案不再变化

以下给出粗略的证明:

因为最短路上最多有n-1条边。所以n-1次松弛后。更新一定引入重边,由此能够构造负环

而假设最短路上不存在负环,则n-1条边构成的字符串最长为6(n-1)

超过6n次松弛后,负环的长度肯定超过6(n-1)。假设没有更新过起点,就再也不会更新了

至于为什么至少须要6n。能够參考下图

时间复杂度: O(VE)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: C.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; const int maxn = 50 + 5;
const int maxe = 500 + 5; int psz;
struct Edge {
int u, v;
string w;
Edge *next;
} epool[maxe]; void add_edge(int u, int v, string w)
{
Edge *p = epool + psz++;
p->u = u; p->v = v; p->w = w;
} int n, m, s, t;
string dis[maxn];
bool vis[maxn]; string bellman_ford()
{
int clk = 0;
memset(vis, false, sizeof(vis));
dis[t] = ""; vis[t] = true;
while (true) {
bool update = false;
for (Edge *i = epool; i < epool + psz; ++i) if (vis[i->v]) {
int u = i->u, v = i->v;
string tmp = i->w + dis[v];
if (!vis[u] || tmp < dis[u]) {
dis[u] = tmp;
update = vis[u] = true;
if (clk >= n - 1 && u == s) return "Tough way!";
}
}
if (!update || ++clk > n * 6) break;
}
return vis[s]? dis[s]: "Tough way!";
} int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
psz = 0;
scanf("%d%d%d%d", &n, &m, &s, &t);
while (m--) {
int u, v;
char buf[8];
scanf("%d%d%s", &u, &v, buf);
add_edge(u, v, buf);
}
printf("Case #%d:\n", ++cas);
puts(bellman_ford().c_str());
} return 0;
}

1004 蜀道难

题目大意

有N座山均匀分布在圆周上,相邻两座山之间的弧长为R,找出距离最远的两个山顶

当中山顶的距离为两座山的高度和,加上两座山沿圆弧的最短距离

算法思路

维护连续区间最值

将环复制一遍后变成链上的问题,不难发现,离某座山最远的山一定在它的前面的N/2座中

所以向右遍历每座山的同一时候。维护向前N/2宽度的区间内的最值。加上当前山的高度更新答案

而将当前高度H插入区间时。须要将区间内的值统一加上R

能够记录一个总的增量D,将H - D插入区间,再将D累加R

这样区间内的大小关系不变,而此时的最值仅仅须要加上D,便可得到实际值

以下的代码中。使用了单调队列维护这一最值

时间复杂度: O(N)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: D.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; typedef pair<int, LL> Pil; const int maxn = 100000 + 5; int n, r, l;
int h[maxn*2]; struct Queue {
LL d;
deque<Pil> deq;
void clear() { d = 0; deq.clear(); }
void push(int i)
{
while (!deq.empty() && h[i] > deq.back().second + d)
deq.pop_back();
deq.push_back(Pii(i, h[i] - d)); d += r;
}
Pil query()
{
Pil res = deq.front(); res.second += d;
return res;
}
void pop(int i)
{
if (!deq.empty() && deq.front().first == i)
deq.pop_front();
}
} que; int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
scanf("%d%d", &n, &r);
l = n / 2;
rep(i,n) scanf("%d", &h[i]), h[n+i] = h[i];
que.clear();
rep(i,l) que.push(i);
LL res = 0; Pii resp;
for (int i = l; i < 2 * n; ++i) {
LL v = que.query().second + h[i];
Pii p = Pii(i % n, que.query().first % n);
if (p.first > p.second) swap(p.first, p.second);
if (v > res) {
res = v; resp = p;
} else if (v == res) {
resp = min(resp, p);
}
que.pop(i - l);
que.push(i);
}
printf("Case #%d:\n", ++cas);
printf("%d %d\n", resp.first + 1, resp.second + 1);
} return 0;
}

1005 最强password

题目大意

给出一个“password生成串”

找到一个“最强password”,不是这个“password生成串”的子序列,而且长度最短

统计“最强password”的个数

算法思路

DP

f[i]表示不是“原串以i结尾前缀”的子序列的最短字符串的长度

g[i]是上述字符串的个数

维护i前面每一个字符最后出现的位置last[]

若存在未出现的字符,则

f[i] = 1

g[i] = 未出现的字符个数

否则

f[i] = min{f[last[j]]} + 1

g[i] = sum{g[last[j]] | f[[last[j]] + 1 == f[i]}

上式的含义为,i之前,以各个字母结尾的,长度为f[i]-1的password串个数的累加

时间复杂度: O(26N)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: E.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; const int mod = 1000000007;
const int maxn = 100000 + 5; int n;
char s[maxn];
int last[26];
int f[maxn], g[maxn]; int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
scanf("%s", s);
n = strlen(s);
memset(last, -1, sizeof(last));
For(i,0,n) {
vector<int> vec;
rep(j,26) if (~last[j]) vec.push_back(last[j]);
if (i < n) last[s[i]-'a'] = i;
if (vec.size() < 26) {
f[i] = 1;
g[i] = 26 - vec.size();
} else {
int t = inf;
foreach(it,vec) t = min(t, f[*it]);
f[i] = t + 1;
g[i] = 0;
foreach(it,vec) if (f[*it] == t)
g[i] = (g[i] + g[*it]) % mod;
}
}
printf("Case #%d:\n", ++cas);
printf("%d %d\n", f[n], g[n]);
} return 0;
}

1006 平衡大师

题目大意

对一张N个点的有向图进行删边。使得每一个点“入度减出度绝对值”的最大值最小

要求至少保留K条边

算法思路

费用流

先考虑最大流

对于有向图,存在总入度等于总出度这一性质,类比于网络流中的流量平衡

因此。从源点向入度大于出度的点连边,而入度小于出度的点连向汇点

因为要达到最大流。前者尽量向网络中流出,而后者则尽量从网络中流入

至于费用

假设给网络中每条边加上为1的费用。则通过网络的流量须要花费代价

回到本题。能够二分每一个点“入度减出度绝对值”的最大值

对于不超过这个值的流量。能够建立一个暂时节点,免费将流量流向此处,或从此处获取流量

而对于超出的部分,依旧仅仅能走网络中通过,带来的费用相当于须要删除的边

此时二分的推断条件为,删除等量于最大流最小费用的边后,是否还留有至少K条边

时间复杂度: O(logV×kVE)

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: F.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-06
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map> using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) typedef long long LL;
typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL; const int maxn = 50 + 5;
const int maxe = 10000 + 5; class Cost_flow {
int n, psz;
struct Edge {
int u, v, r, c;
Edge *next, *cp;
} epool[maxe], *e[maxn];
int s, t, dist, cost;
int dis[maxn];
bool inq[maxn], vis[maxn]; bool modlable()
{
deque<int> deq;
memset(dis, 0x3f, sizeof(dis));
memset(inq, false, sizeof(inq));
dis[t] = 0; inq[t] = true; deq.push_back(t);
while (!deq.empty()) {
int u = deq.front(); deq.pop_front(); inq[u] = false;
for (Edge *i = e[u]; i; i = i->next) if (i->cp->r) {
int v = i->v;
if (dis[v] <= dis[u] - i->c) continue;
dis[v] = dis[u] - i->c;
if (inq[v]) continue; inq[v] = true;
deq.empty() || dis[v] < dis[deq.front()]? deq.push_front(v): deq.push_back(v);
}
}
for (int u = 0; u < n; ++u)
for (Edge *i = e[u]; i; i = i->next)
i->c += dis[i->v] - dis[u];
dist += dis[s];
return dis[s] < inf;
} int aug(int u, int m)
{
if (u == t) return cost += dist * m, m;
int f = 0; vis[u] = true;
for (Edge *i = e[u]; i; i = i->next) {
int v = i->v;
if (i->r && !i->c && !vis[v]) {
int d = aug(v, min(i->r, m));
i->r -= d; i->cp->r += d; m -= d; f += d;
if (!m) break;
}
}
return f;
} public:
void init(int n)
{
this->n = n; psz = 0;
memset(e, 0, sizeof(e));
} void add_edge(int u, int v, int w, int c)
{
Edge *i = epool + psz;
i->v = v; i->r = w; i->c = c; i->next = e[u]; e[u] = i;
i->cp = epool + (psz++ ^ 1);
if (psz & 1) add_edge(v, u, 0, -c);
} int min_cost(int s, int t, int &flow)
{
this->s = s; this->t = t; dist = cost = flow = 0;
while (modlable()) {
int d;
do {
memset(vis, false, sizeof(vis));
flow += (d = aug(s, inf));
} while (d);
}
return cost;
}
} grp; int n, m, k, tot;
int u[maxe], v[maxe], deg[maxn];
map<string, int> id; int get_id(string s)
{
if (id.count(s)) return id[s];
return id[s] = tot++;
} bool check(int c)
{
grp.init(n + 3);
int src = n, trg = n + 1, tmp = n + 2;
rep(i,m) grp.add_edge(u[i], v[i], 1, 1);
rep(i,n) {
if (deg[i] > 0) {
grp.add_edge(src, i, deg[i], 0);
grp.add_edge(i, tmp, c, 0);
}
if (deg[i] < 0) {
grp.add_edge(i, trg, -deg[i], 0);
grp.add_edge(tmp, i, c, 0);
}
}
return m - grp.min_cost(src, trg, tmp) >= k;
} int main()
{
int T, cas = 0;
scanf("%d", &T); while (T--) {
scanf("%d%d%d", &n, &m, &k);
tot = 0;
id.clear();
memset(deg, 0, sizeof(deg));
rep(i,m) {
char s[24];
scanf("%s", s);
u[i] = get_id(s);
scanf("%s", s);
v[i] = get_id(s);
++deg[u[i]], --deg[v[i]];
}
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("Case #%d:\n", ++cas);
printf("%d\n", r);
} return 0;
}

2015 Astar Contest - Round 3 题解的更多相关文章

  1. Codeforces Round #556 题解

    Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...

  2. Codeforces Round #569 题解

    Codeforces Round #569 题解 CF1179A Valeriy and Deque 有一个双端队列,每次取队首两个值,将较小值移动到队尾,较大值位置不变.多组询问求第\(m\)次操作 ...

  3. Codeforces Round #557 题解【更完了】

    Codeforces Round #557 题解 掉分快乐 CF1161A Hide and Seek Alice和Bob在玩捉♂迷♂藏,有\(n\)个格子,Bob会检查\(k\)次,第\(i\)次检 ...

  4. 2018 ACM-ICPC Asia Beijing Regional Contest (部分题解)

    摘要 本文主要给出了2018 ACM-ICPC Asia Beijing Regional Contest的部分题解,意即熟悉区域赛题型,保持比赛感觉. Jin Yong’s Wukong Ranki ...

  5. 2014-2015 ACM-ICPC, Asia Xian Regional Contest(部分题解)

    摘要 本文主要给出了2014-2015 ACM-ICPC, Asia Xian Regional Contest的部分题解,说明了每题的题意.解题思路和代码实现,意即熟悉区域赛比赛题型. Built ...

  6. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

  7. Comet OJ - Contest #2简要题解

    Comet OJ - Contest #2简要题解 前言: 我没有小裙子,我太菜了. A 因自过去而至的残响起舞 https://www.cometoj.com/contest/37/problem/ ...

  8. LibreOJ β Round #2 题解

    LibreOJ β Round #2 题解 模拟只会猜题意 题目: 给定一个长为 \(n\) 的序列,有 \(m\) 次询问,每次问所有长度大于 \(x\) 的区间的元素和的最大值. \(1 \leq ...

  9. 300iq Contest 1 简要题解

    300iq Contest 1 简要题解 咕咕咕 codeforces A. Angle Beats description 有一张\(n\times m\)的方阵,每个位置上标有*,+,.中的一种. ...

随机推荐

  1. java基础(1-50)-------->超级简单,不信你不会!!!

    1:java中的保留字:const&goto; 2:&和&&都可以做逻辑运算符,即运算符两边的表达式都为true,结果才为true,一方为false,则结果为false ...

  2. C++学习(一):现代C++尝试

    C++是一门与时俱进的语言. 早期的C++关注的主要问题是通用性,却没有太多关注易用性的问题,使得C++成为了一门多范式语言,但是使用门槛较高. 从2011开始,C++的标准进行了较大的更新,开始更多 ...

  3. hdu 4994(博弈)

    Revenge of Nim Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. Linux每日一坑001

    centos6,7中网卡/etc/sysconfig/network-scripts/ifcfg-eth0的命名是有要求的,必须是ifcfg-开头.改网卡名的时候掉坑.

  5. 对动态规划(Dynamic Programming)的理解:从穷举开始(转)

    转自:http://janfan.cn/chinese/2015/01/21/dynamic-programming.html 动态规划(Dynamic Programming,以下简称dp)是算法设 ...

  6. 莫队浅谈&题目讲解

    莫队浅谈&题目讲解 一.莫队的思想以及莫队的前置知识 莫队是一种离线的算法,他的实现借用了分块的思想.在学习莫队之前,本人建议学习一下分块,并对其有一定的理解. 二.莫队 现给出一道例题:bz ...

  7. 【freeCodeCamp】免费晋级前台工程师呦!!!!

    首页地址:https://www.freecodecamp.org/ GitHub:https://github.com/freeCodeCamp/freeCodeCamp ============= ...

  8. EasyMvc入门教程-高级控件说明(18)弹出框控件

    前面两节介绍了信息框与对话框,实际开发中如果我们遇到更复杂的要求,比如要求在弹出框里显示另外的网址,如下所示: 实现代码如下: @Html.Q().Popup().Text("我可以嵌套网页 ...

  9. 【重点突破】—— Vue1.0到Vue2.0的变化

    前言: 本文参考作者:_So_ 和 我是某慧 的博文,重点梳理Vue1.0升级到Vue2.0后在开发中要注意的不同,以做学习.        组件模板不再支持片段代码,必须有一个顶级元素包裹,例如: ...

  10. 给交换机端口设ip

    先给端口设vlan,再给vlan设ip [H3C]vlan [H3C-vlan100]port GigabitEthernet // <H3C>sy System View: return ...