Educational Codeforces Round 40 A B C D E G
A. Diagonal Walking
题意
将一个序列中所有的\('RU'\)或者\('UR'\)替换成\('D'\),问最终得到的序列最短长度为多少。
思路
贪心
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 110
using namespace std;
char s[maxn];
typedef long long LL;
int main() {
int n, cnt=0;
scanf("%d%s", &n, s);
bool used=0;
F(i, 1, n) {
if (!used && ((s[i]=='U'&&s[i-1]=='R') || (s[i]=='R'&&s[i-1]=='U'))) {
++cnt, used = true;
}
else used = false;
}
printf("%d\n", n-cnt);
return 0;
}
B. String Typing
题意
要得到一个字符串,有两种操作:
- 打印一个字符
- 将前面打印过的部分拷贝一遍跟在后面;
第二种方法最多只能使用一次。
问要打印一个字符串最少的操作次数。
思路
数据量暴力可过,但是还是拿来回忆了下后缀数组。
题目即是要求最长的\(A\),使得原字符串\(S\)可表示为\(AAB\)的形式。
通过后缀数组的\(height\)数组,可以知道原串与每一个后缀的\(LCP\)长度,要能够拷贝,满足的条件是:
- 该后缀与原串的\(LCP\)长度\(\geq\)两者之间的起始位置差
- 该后缀与原串间的起始位置差\(*2\leq\)原串的长度
在所有满足条件的当中取个最大值即可。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 1010
using namespace std;
int wa[maxn], wb[maxn], wv[maxn], wt[maxn], h[maxn], rk[maxn], sa[maxn], n, m, tot, r[maxn];
char s[maxn];
bool cmp(int* r, int a, int b, int l) { return r[a] == r[b] && r[a+l] == r[b+l]; }
void init(int* r, int* sa, int n, int m) {
int* x=wa, *y=wb, *t, i, j, p;
for (i = 0; i < m; ++i) wt[i] = 0;
for (i = 0; i < n; ++i) ++wt[x[i] = r[i]];
for (i = 1; i < m; ++i) wt[i] += wt[i - 1];
for (i = n-1; i >= 0; --i) sa[--wt[x[i]]] = i;
for (j = 1, p = 1; p < n; j <<= 1, m = p) {
for (p = 0, i = n-j; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = 0; i < n; ++i) wv[i] = x[y[i]];
for (i = 0; i < m; ++i) wt[i] = 0;
for (i = 0; i < n; ++i) ++wt[wv[i]];
for (i = 1; i < m; ++i) wt[i] += wt[i - 1];
for (i = n-1; i >= 0; --i) sa[--wt[wv[i]]] = y[i];
t = x, x = y, y = t, x[sa[0]] = 0;
for (p = 1, i = 1; i < n; ++i) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? p - 1 : p++;
}
for (i = 0; i < n; ++i) rk[sa[i]] = i;
int k = 0;
for (i = 0; i < n - 1; h[rk[i++]] = k) {
for (k = k ? --k : 0, j = sa[rk[i] - 1]; r[i+k] == r[j+k]; ++k);
}
}
int main() {
scanf("%d%s", &n, s);
F(i, 0, n) m = max(r[tot++]=s[i], m); r[tot++] = 0;
init(r, sa, tot, ++m);
int p = rk[0], maxx = 0;
dF2(i, p-1, 1) {
if (h[i+1]>=sa[i] && (sa[i]<<1)<=n) maxx = max(maxx, sa[i]);
h[i] = min(h[i], h[i+1]);
}
F(i, p+1, tot) {
if (h[i]>=sa[i] && (sa[i]<<1)<=n) maxx = max(maxx, sa[i]);
h[i+1] = min(h[i], h[i+1]);
}
printf("%d\n", maxx?n-maxx+1:n);
return 0;
}
C. Matrix Walk
题意
一个\(N\times M\)的方格纸,从左到右从上到下分别标号\(1,2,\ldots,N\times M\). 在每一个格子中只能向上下左右相邻的四个格子走。
现给出一个行走序列,要求给出一组合法的\(N,M\). 或者指出不存在。
思路
注意到,合法的序列差只可能为\(1\)或者定值\(M\).
在满足该条件的基础上,还要注意不能从最右边的格子\(+1\),不能从最左边的格子\(-1\).
注意一些细节即可。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 200010
using namespace std;
typedef long long LL;
int a[maxn];
int main() {
int n, y;
scanf("%d", &n);
F(i, 0, n) scanf("%d", &a[i]);
F(i, 1, n) {
y = abs(a[i]-a[i-1]);
if (y==0) { puts("NO"); return 0; }
if (y>1) break;
}
if (y==1) { puts("YES"); printf("%d %d\n", 1, 1000000000); }
else {
F(i, 1, n) {
if (a[i]-a[i-1]==1) {
if (a[i-1]%y==0) { puts("NO"); return 0; }
}
else if (a[i]-a[i-1]==-1) {
if (a[i]%y==0) { puts("NO"); return 0; }
}
else if (abs(a[i]-a[i-1])!=y) { puts("NO"); return 0; }
}
puts("YES");
printf("%d %d\n", 1000000000, y);
}
return 0;
}
D. Fight Against Traffic
题意
给定一张图和起点\(s\)终点\(t\),现在原图不相邻的两点之间加一条边,问有多少种加边方式会不导致\(s\)到\(t\)之间的距离缩短。
思路
若加边导致距离缩短,则必经过刚加的边,假设加的边为\((u,v)\),原\(s,t\)的距离为\(d\),图中所有顶点到\(s\)的最短路距离为\(dist1[]\),到\(t\)的最短路距离为\(dist2[]\)则必有$$dist1[u]+1+dist2[v]\lt d$$或者
\]
枚举边根据上述条件\(check\)即可。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 1010
struct Edge { int to, ne; }edge[maxn<<1];
int tot, ne[maxn], dist1[maxn], dist2[maxn];
bool vis[maxn], mp[maxn][maxn];
void add(int u, int v) {
edge[tot] = {v, ne[u]};
ne[u] = tot++;
}
struct node {
int v, c;
bool operator < (const node& nd) const { return c > nd.c; }
};
using namespace std;
typedef long long LL;
void dij(int src, int* dist) {
memset(vis, 0, sizeof vis);
memset(dist, 0x3f, maxn*sizeof(int));
vis[src] = true; dist[src] = 0;
priority_queue<node> q;
while (true) {
for (int i = ne[src]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (vis[v]) continue;
if (dist[src]+1<dist[v]) {
dist[v] = dist[src]+1;
q.push({v, dist[v]});
}
}
while (!q.empty() && vis[q.top().v]) q.pop();
if (q.empty()) break;
vis[src=q.top().v] = true;
}
}
int main() {
memset(ne, -1, sizeof ne);
int n, m, s, t, u, v;
scanf("%d%d%d%d", &n, &m, &s, &t);
F(i, 0, m) {
scanf("%d%d", &u, &v);
add(u, v), add(v, u);
mp[u][v] = mp[v][u] = true;
}
dij(s, dist1);
dij(t, dist2);
int cur = dist1[t], ans = 0;
F2(i, 1, n) {
F2(j, i+1, n) {
if (mp[i][j]) continue;
if (dist1[i]+1+dist2[j]>=cur && dist2[i]+1+dist1[j]>=cur) ++ans;
}
}
printf("%d\n", ans);
return 0;
}
E. Water Taps
题意
\(n\)个水龙头,流量分别为\(a_1,a_2,\ldots,a_n\),温度分别为\(t_1,t_2,\ldots,t_n\),打开若干个水龙头放水,假设放出的水量分别为\(x_1,x_2,\ldots,x_n\),则得到的水温为
\]
现要得到温度为\(T\)的水,求能放出的水量的最大值。
思路
因为
\]
所以
\]
因此将所有的\(t_i\)减去\(T\)之后,每个水龙头对温度的贡献就分为正贡献和负贡献。
正的放在一边,负的放在一边,因为能取小数,所以少的一边必能取满。
而要多的那边能取到尽量多的\(x\),只要\(t\)尽量小,所以将\(t\)从小到大排序后取即可。
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 200010
using namespace std;
typedef long long LL;
struct node {
LL x, t;
bool operator < (const node& nd) const { return t < nd.t; }
}a[maxn];
int main() {
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int n, T;
scanf("%d%d", &n, &T);
F(i, 0, n) scanf("%I64d", &a[i].x);
F(i, 0, n) scanf("%I64d", &a[i].t), a[i].t-=T;
sort(a, a+n);
int p2=0, p1=-1;
double ans=0;
for (; p2<n; ++p2) {
if (a[p2].t<0) p1=p2;
else if (!a[p2].t) ans += a[p2].x;
if (a[p2].t > 0) break;
}
if (p1==-1||p2==n) printf("%.8f\n", ans);
else {
LL sum1=0, sum2=0;
dF2(i, p1, 0) sum1-=a[i].x*a[i].t;
F(i, p2, n) sum2+=a[i].x*a[i].t;
if (sum1>=sum2) {
F(i, p2, n) ans += a[i].x;
int i=p1;
for (; i >= 0; --i) {
if (sum2-a[i].x*(-a[i].t)<0) break;
ans += a[i].x;
sum2 += a[i].x*a[i].t;
}
if (i>=0&&sum2) ans += 1.0*sum2/(-a[i].t);
}
else {
dF2(i, p1, 0) ans += a[i].x;
int i=p2;
for (; i < n; ++i) {
if (sum1-a[i].x*a[i].t<0) break;
ans += a[i].x;
sum1 -= a[i].x*a[i].t;
}
if (i<n&&sum1) ans += 1.0*sum1/a[i].t;
}
printf("%.8f\n", ans);
}
return 0;
}
G. Castle Defense
题意
数轴上\(n\)个位置每个位置放有若干个弓箭手,弓箭手的攻击范围为左右大小为\(r\)的范围内。
一个点的防御程度定义为 该点能被多少个弓箭手攻击到。整条放线的防御程度定义为其上所有点防御程度的 最小值。
现可以在防线上增添\(k\)个弓箭手,要求使防线的防御程度最大化,求这个最大值。
思路
最小值的最大值,首先显然二分答案。
对于初始固定的弓箭手,一段一段的线段覆盖,可以用前缀和差分来处理。
之后二分答案时的\(check\)怎么进行呢?
用一个变量记录至今为止多放置了多少个弓箭手,从左到右扫
- 若位置\(i\)不够,则要在位置\(i+r+1\)补弓箭手
- 考虑到位置\(i\)时,要记得消除掉前面的\(i-r-1\)位置的影响
复杂度\(O(n\log n)\)
Code
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 500010
using namespace std;
typedef long long LL;
int n, d; LL k;
LL sum[maxn], a[maxn], add[maxn];
bool check(LL x) {
memset(add, 0, sizeof add);
LL temp=0, tot=0;
F2(i, 1, n) {
temp -= (i>=d+2 ? add[i-d-1] : 0);
if (x<=sum[i]+temp) continue;
int p = min(i+d, n);
add[p] = x - (sum[i] + temp);
tot += add[p];
if (tot>k) return false;
temp = x-sum[i];
}
return true;
}
int main() {
scanf("%d%d%I64d", &n, &d, &k);
F2(i, 1, n) {
scanf("%I64d", &a[i]);
int l=max(i-d, 1), r=min(n+1, i+d+1);
sum[l]+=a[i], sum[r]-=a[i];
}
F2(i, 1, n) sum[i] += sum[i-1];
LL l=0, r=2e18, ans;
while (l<=r) {
LL mid=l+r>>1;
if (check(mid)) ans=mid, l=mid+1;
else r=mid-1;
}
printf("%I64d\n", ans);
return 0;
}
Educational Codeforces Round 40 A B C D E G的更多相关文章
- Educational Codeforces Round 40 (Rated for Div. 2) 954G G. Castle Defense
题 OvO http://codeforces.com/contest/954/problem/G 解 二分答案, 对于每个二分的答案值 ANS,判断这个答案是否可行. 记 s 数组为题目中描述的 a ...
- Educational Codeforces Round 40 F. Runner's Problem
Educational Codeforces Round 40 F. Runner's Problem 题意: 给一个$ 3 * m \(的矩阵,问从\)(2,1)$ 出发 走到 \((2,m)\) ...
- Educational Codeforces Round 40千名记
人生第二场codeforces.然而遇上了Education场这种东西 Educational Codeforces Round 40 下午先在家里睡了波觉,起来离开场还有10分钟. 但是突然想起来还 ...
- Educational Codeforces Round 40 C. Matrix Walk( 思维)
Educational Codeforces Round 40 (Rated for Div. 2) C. Matrix Walk time limit per test 1 second memor ...
- Educational Codeforces Round 40 (Rated for Div. 2) Solution
从这里开始 小结 题目列表 Problem A Diagonal Walking Problem B String Typing Problem C Matrix Walk Problem D Fig ...
- Educational Codeforces Round 40 I. Yet Another String Matching Problem
http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...
- Educational Codeforces Round 40 G. Castle Defense (二分+滑动数组+greedy)
G. Castle Defense time limit per test 1.5 seconds memory limit per test 256 megabytes input standard ...
- Educational Codeforces Round 40 (Rated for Div. 2)
A. Diagonal Walking time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Educational Codeforces Round 58 A,B,C,D,E,G
A. Minimum Integer 链接:http://codeforces.com/contest/1101/problem/A 代码: #include<bits/stdc++.h> ...
随机推荐
- 『Golang』MongoDB在Golang中的使用(mgo包)
有关在Golang中使用mho进行MongoDB操作的最简单的例子.
- win10 java环境变量配置
首先,你应该已经安装了 Java 的 JDK 了(如果没有安装JDK,请跳转到此网址:http://www.oracle.com/technetwork/java/javase/downloads/i ...
- java文件的I/O
[原创] java文件的I/O操作,简单来说就是向文件中写入数据以及从文件中读出数据,这是我们平日做的最多的操作,这里给出两种文件I/O操作,当然还有许多的操作方法,各种流的使用,可谓是高深莫测:不管 ...
- POI实现excel的数据验证
目录 前言 难点1:合并单元格 代码实现策略: step 1: 合并单元格 step 2: 给单元格赋值 难点2:数据验证-下拉框 代码实现策略: step 1:设置需要进行数据验证的单元格范围和可供 ...
- C语言单元测试
转自http://blog.csdn.net/colin719/article/details/1420583 对于敏捷开发来说,单元测试必不可少,对于Java开发来说,JUnit非常好,对于C++开 ...
- WCF 透明代理
现在我们通过类似的原理创建一个用于模拟WCF服务端和客户端工作原理的模拟程序.[源代码从这里下载] 目录 一.基本的组件和执行流程 二.创建自定义HttpHandler实现对服务调用请求的处理 三.定 ...
- 基于log4j的消息流的实现之一消息获取
需求: 目前的程序中都是基于log4j来实现日志的管理,想要获取日志中的一部分消息,展示给用户. 约束: 由于程序中除了自己开发的代码,还会有层层依赖的第三方jar中的日志输出.需要展示给用户的消息, ...
- systemtap get var of the tracepoing
kernel.trace("sched_switch") func:func:perf_trace_sched_stat_template get the function in ...
- 算法(2) Find All Numbers Disappeared in an Array
题目:整数数组满足1<=a[i]<=n(n是数组的长度),某些元素出现一次,某些元素出现两次,在数组a[i]中找到[1,n]区间中未出现的数字.比如输入[4,3,2,7,8,2,3,1], ...
- 【bzoj1123】[POI2008]BLO DFS树
题目描述 Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 所有towns连通. 输入 输入n<=100000 ...