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

题意

要得到一个字符串,有两种操作:

  1. 打印一个字符
  2. 将前面打印过的部分拷贝一遍跟在后面;

    第二种方法最多只能使用一次

问要打印一个字符串最少的操作次数。

思路

数据量暴力可过,但是还是拿来回忆了下后缀数组。

题目即是要求最长的\(A\),使得原字符串\(S\)可表示为\(AAB\)的形式。

通过后缀数组的\(height\)数组,可以知道原串与每一个后缀的\(LCP\)长度,要能够拷贝,满足的条件是:

  1. 该后缀与原串的\(LCP\)长度\(\geq\)两者之间的起始位置差
  2. 该后缀与原串间的起始位置差\(*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$$或者

\[dist1[v]+1+dist2[u]\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\),则得到的水温为

\[\frac{\sum_{i=1}^{n}x_it_i}{\sum_{i=1}^{n}x_i}
\]

现要得到温度为\(T\)的水,求能放出的水量的最大值。

思路

因为

\[\frac{\sum_{i=1}^{n}x_it_i}{\sum_{i=1}^{n}x_i}=T
\]

所以

\[\sum_{i=1}^{n}x_i(t_i-T)=0
\]

因此将所有的\(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\)怎么进行呢?

用一个变量记录至今为止多放置了多少个弓箭手,从左到右扫

  1. 若位置\(i\)不够,则要在位置\(i+r+1\)补弓箭手
  2. 考虑到位置\(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的更多相关文章

  1. Educational Codeforces Round 40 (Rated for Div. 2) 954G G. Castle Defense

    题 OvO http://codeforces.com/contest/954/problem/G 解 二分答案, 对于每个二分的答案值 ANS,判断这个答案是否可行. 记 s 数组为题目中描述的 a ...

  2. Educational Codeforces Round 40 F. Runner's Problem

    Educational Codeforces Round 40 F. Runner's Problem 题意: 给一个$ 3 * m \(的矩阵,问从\)(2,1)$ 出发 走到 \((2,m)\) ...

  3. Educational Codeforces Round 40千名记

    人生第二场codeforces.然而遇上了Education场这种东西 Educational Codeforces Round 40 下午先在家里睡了波觉,起来离开场还有10分钟. 但是突然想起来还 ...

  4. 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 ...

  5. Educational Codeforces Round 40 (Rated for Div. 2) Solution

    从这里开始 小结 题目列表 Problem A Diagonal Walking Problem B String Typing Problem C Matrix Walk Problem D Fig ...

  6. Educational Codeforces Round 40 I. Yet Another String Matching Problem

    http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...

  7. 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 ...

  8. 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 ...

  9. Educational Codeforces Round 58 A,B,C,D,E,G

    A. Minimum Integer 链接:http://codeforces.com/contest/1101/problem/A 代码: #include<bits/stdc++.h> ...

随机推荐

  1. 「暑期训练」「Brute Force」 Far Relative’s Problem (CFR343D2B)

    题意 之后补 分析 我哭了,强行增加自己的思考复杂度...明明一道尬写的题- -(往区间贪心方向想了 其实完全没必要,注意到只有366天,直接穷举判断即可. 代码 #include <bits/ ...

  2. cpp语言程序设计教程第七章的一道编程题

    题目如下 按下列要求实现一个有关学生成绩的操作. 该类名为Student. (1)每个学生的信息包含有姓名(字符数组)和成绩(int型). (2)共有5个学生,用对象数组表示. (3)计算出5个学生中 ...

  3. 【转】webpack4

    1.不再支持node.js4.X 2.不能用webpack命令直接打包指定的文件,只能使用webpack.config.js进行配置. 即:webpack  demo01.js  bundle01.j ...

  4. centos7 centos6中 更改默认的系统启动级别

    centos6中更改默认的启动级别 方法: 1.vi /etc/inittab 2.找到id:x:initdefault:,我的系统是id:3:initdefault:,即默认以字符模式启动. 3.将 ...

  5. 自定义Json格式

    老铁们都知道,一般的json格式就是键值对格式,在一些特定的框架或者系统中,会用到自定义格式的json文件,假设我们要得到的特定格式json格式如下: {"A":"2&q ...

  6. hash function比较

    http://blog.csdn.net/kingstar158/article/details/8028635 由于工作需要,针对千万级别的数据,使用stl::map着实存在着效率问题,最后使用bo ...

  7. 一种保持顺序的Properties

    其实properties有没有顺序都一样 程序都能正常运行 但看着就比较闹心 所以网上找了找 还真有人给了个例子实现读Property的有序 但是删除某些属性之后 写入又有问题 会异常 后来重写了一下 ...

  8. 使用ExecutorService实现线程池

    ExecutorService是java提供的用于管理线程池的类. 线程池的作用: - 控制线程数量 - 重用线程 当一个程序中创建了许多线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切 ...

  9. 输入的是util包下面的 时间, 接受的是java.sql.date 或者 java.util.date类型

  10. 2017 Multi-University Training Contest - Team 3 RXD and functions(NTT)

    题解: 我是参考的 http://blog.csdn.net/qq_32570675/article/details/76571666 这一篇 orz 原来可以这么变换,涨姿势 代码: #includ ...