A. Toy Train

  • 时间限制:2 seconds
  • 内存限制:256 megabytes

题意

有编号111~n(n≤5000)n(n\le 5000)n(n≤5000)的车站顺时针呈环排列,有m(m≤20000)m(m\le 20000)m(m≤20000)个糖果需要运送到指定位置。每个糖果由(a[i],b[i])(a[i],b[i])(a[i],b[i])表示,其中a[i]≠b[i]a[i]=\not b[i]a[i]≠​b[i],指这个糖果最初位置和需要运送到的位置。列车只能顺时针行驶,行驶到相邻站台所用时间为111。每到一个站台,最多只能取走一个糖果放在车上,这个糖果可以随便选。而卸下糖果的数量不限制。询问列车从每个位置出发把所有糖果都运送到指定位置的最短时间。

下图中蓝色的数字就表示该糖果要去的位置。

分析

假设第iii个车站有sz[i]sz[i]sz[i]个糖果,显然对于这个车站必须要至少经过sz[i]sz[i]sz[i]次。那么决定最后在哪个地方停止一定是最后一个糖果。根据贪心的策略,我们只要把最近的糖果最后取就行了。

所以我们枚举起始点iii,再枚举每一个车站jjj,如果jjj车站有糖果的话,取完车站jjj的至少需要走的时间就是dist(i,j)+(sz[j]−1)∗n+min⁡a[k]=jdist(j,b[k])dist(i,j)+(sz[j]-1)*n+\min \limits_{a[k]=j} dist(j, b[k])dist(i,j)+(sz[j]−1)∗n+a[k]=jmin​dist(j,b[k])。所有的取最大值就是答案了。

dist(i,j)dist(i,j)dist(i,j)表示从iii走到jjj的距离,具体值等于(j−i+n)%n(j-i+n)\%n(j−i+n)%n

代码如下

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
int n, m, sz[MAXN], mn[MAXN];
inline int dist(const int &A, const int &B) { return B >= A ? B-A : n+B-A; }
int main () {
scanf("%d%d", &n, &m);
memset(mn, 0x7f, sizeof mn);
for(int x, y, i = 1; i <= m; ++i) {
scanf("%d%d", &x, &y); ++sz[x];
mn[x] = min(mn[x], dist(x, y));
}
for(int i = 1; i <= n; ++i) {
int ans = 0;
for(int j = 1; j <= n; ++j) if(sz[j])
ans = max(ans, dist(i, j) + n*(sz[j]-1) + mn[j]);
printf("%d ", ans);
}
}

B. Wrong Answer

  • 时间限制:1 seconds
  • 内存限制:256 megabytes

    这题目好啊

题意

有这样一个问题,给出长度为nnn的整数序列aaa,求max⁡1≤l≤r≤n∑l≤i≤r(r−l+1)∗ai\large \max \limits_{1\le l\le r\le n} \sum_{l\le i\le r}(r-l+1)*a_i1≤l≤r≤nmax​∑l≤i≤r​(r−l+1)∗ai​。

其中n≤2000,∣ai∣≤106n\le2000,|a_i|\le10^6n≤2000,∣ai​∣≤106。

AliceAliceAlice同学玩够各类博弈游戏发现自己老是输给BobBobBob,决定卧薪尝胆好好刷题。她遇到了这个问题,然后写了这样一个代码:

function find_answer(n, a)
# Assumes n is an integer between 1 and 2000, inclusive
# Assumes a is a list containing n integers: a[0], a[1], ..., a[n-1]
res = 0
cur = 0
k = -1
for i = 0 to i = n-1
cur = cur + a[i]
if cur < 0
cur = 0
k = i
res = max(res, (i-k)*cur)
return res

显然这个代码是Wrong Answer\color{red}{Wrong\ Answer}Wrong Answer的。举个例子,假设n=4n=4n=4 且 a=[6,−8,7,−42]a=[6,−8,7,−42]a=[6,−8,7,−42]。那么find_answer(n,a)find\_answer(n, a)find_answer(n,a) 得到的答案是 777, 然正确答案是3⋅(6−8+7)=153⋅(6−8+7)=153⋅(6−8+7)=15。

给出k(1≤k≤109)k(1\le k\le 10^9)k(1≤k≤109),你要构造一组数据,使得AliceAliceAlice的答案和正确答案相差恰好为kkk。你构造的序列必须也满足上面所说的n≤2000,∣ai∣≤106n\le2000,|a_i|\le10^6n≤2000,∣ai​∣≤106。如果不存在请输出−1-1−1。

分析

可以看出AliceAliceAlice的程序只统计了非负数的区间。那么我们只需要搞一个−1-1−1在最前面,然后让后面序列的和SumSumSum尽量的大。这是AliceAliceAlice的答案一定是的和SumSumSum乘以后面的长度LLL,但是多取这个−1-1−1会让答案变成(Sum−1)∗(L+1)=Sum∗L+Sum−L−1(Sum-1)*(L+1)=Sum*L+Sum-L-1(Sum−1)∗(L+1)=Sum∗L+Sum−L−1。我们只要保证Sum−L−1=kSum-L-1=kSum−L−1=k就行了,即Sum=L+1+kSum=L+1+kSum=L+1+k。

那么我们构造出来的序列除去前面的-1就是长度为LLL,和为L+1+kL+1+kL+1+k的序列。因为我们实际上是可以补0的,那么要让后面的LLL个数和为L+1+kL+1+kL+1+k。只要前面尽量放10610^6106,就行了。不过由于这个10610^6106的限制,要求L+1+kL≤106\large \frac{L+1+k}L\le 10^6LL+1+k​≤106,因为k≤109k\le10^9k≤109,L≤2000L\le 2000L≤2000,所以LLL随便取个120012001200就行了。

代码如下

#include <bits/stdc++.h>
using namespace std;
int main () {
int k;
scanf("%d", &k);
//sum*1200 = (sum-1)*1201 - k
//sum = k + 1201
int sum = k + 1201;
printf("1201\n-1");
for(int i = 1; i <= 1200; ++i) {
int ans = min(1000000, sum);
sum -= ans;
printf(" %d", ans);
}
}

C. Morse Code

  • 时间限制:2 seconds
  • 内存限制:256 megabytes

题意

把二十六个字母的摩尔斯电码用二进制表示就是一些010101串。摩尔斯电码长度从111~444不等,但是这样算出来是21+22+23+24=30=26+42^1+2^2+2^3+2^4=30=26+421+22+23+24=30=26+4,那么就有444个串没有所代表的字母。它们分别是"001100110011","010101010101","111011101110",和"111111111111"。

最初你有一个空串,有n(n≤3000)n(n\le 3000)n(n≤3000)次添加,每次添加1/01/01/0,每添加一次都要输出当前得到的串的所有子串能够翻译出的不同的字母串的数量,答案膜109+710^9+7109+7输出。比如"111"能够翻译出的就是这些:

“T” (translates into “1”)

“M” (translates into “11”)

“O” (translates into “111”)

“TT” (translates into “11”)

“TM” (translates into “111”)

“MT” (translates into “111”)

“TTT” (translates into “111”)

分析

假设你有一个固定的串,求它能够翻译出的不同字母串的dp还是很好想的。时间复杂度是O(len∗4)O(len*4)O(len∗4)。那么一个暴力的想法就是枚举每个不同子串做dp,这样dp的总时间复杂度是O(n3)O(n^3)O(n3)。

然而我们发现当左端点lll固定的时候,右端点rrr递增时其实可以一起dp的。那么对于左端点固定的子串,dp就是O(n)O(n)O(n)的。

然而这个是每一次在最后添加一个字符。不能固定左端点。

怎么办呢?

那就固定右端点倒着dp呗。

然后我判重用hash+maphash+maphash+map,多了一个logloglog再加上dp有个444的常数就TLETLETLE了。

怎么办呢,这时候又用到上面那个共用的思想(…),我们用trie树来判010101串的重,如果到最后一个字符的个节点已经有值了那么已经算过,就不加到答案里面;否则就统计答案。右端点固定的话左端点递减的串在trie树上是一条路径,这样的话插入这些右端点固定的子串时间复杂度就是O(n)O(n)O(n)的了。

右端点有nnn个,那么总时间复杂度就是O(n2)O(n^2)O(n2)的了。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3010;
const int mod = 1e9 + 7;
int n, x[MAXN], dp[MAXN], ans, trie[MAXN*MAXN][2];
inline bool chk(int i) {
if(!x[i-3] && !x[i-2] && x[i-1] && x[i]) return 0;
if(!x[i-3] && x[i-2] && !x[i-1] && x[i]) return 0;
if(x[i-3] && x[i-2] && x[i-1] && !x[i]) return 0;
if(x[i-3] && x[i-2] && x[i-1] && x[i]) return 0;
return 1;
}
inline void add(int &x, int y) { x += y; if(x >= mod) x -= mod; }
int main () {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &x[i]);
int rt = 1, cnt = 1;
for(int i = 1; i <= n; ++i) {
dp[i+1] = 1;
int r = rt;
for(int j = i; j; --j) {
dp[j] = 0;
add(dp[j], dp[j+1]);
add(dp[j], dp[j+2]);
add(dp[j], dp[j+3]);
if(chk(j+3)) add(dp[j], dp[j+4]);
if(!trie[r][x[j]]) trie[r][x[j]] = ++cnt, add(ans, dp[j]);
r = trie[r][x[j]];
}
printf("%d\n", ans);
}
}

D. Isolation

  • 时间限制:3 seconds
  • 内存限制:256 megabytes

题意

给出长度为n(1≤n≤105)n(1\le n\le 10^5)n(1≤n≤105)的数组a(ai≤n)a(a_i\le n)a(ai​≤n)。给出1≤k≤n1\le k\le n1≤k≤n。求把这个序列分成若干块的方案,使得对于每个区间,只出现一次的数字不超过kkk个。

分析

首先暴力O(n2)O(n^2)O(n2)dp很好想的,转移方程式为:

dp[i]+=dp[j−1] 且(i,j)dp[i]+=dp[j-1]\ 且(i,j)dp[i]+=dp[j−1] 且(i,j)中只出现一次的数不超过kkk个

我们看看怎么记录只出现一次的数的个数,就是从后往前扫,遇到数的第一次+1,第二次-1,然后做一个后缀和就行了。那么对于后缀和≤k\le k≤k的位置jjj,j−1j-1j−1就能够当作决策点。为了方便我们把dp[]dp[]dp[]的下标同时加一就行了。

这样的话每往后移动就修改两个区间(画画就知道了),区间修改可以用线段树,但是穿插着查询的话无法处理,于是分块做。每个块存一下后缀和为每个值的dpdpdp值的和,也要存一下后缀和≤k\le k≤k的dpdpdp值的和,也就是这个块内的答案。也要维护懒标记。

时间复杂度O(nn)O(n\sqrt n)O(nn​)

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
const int MAXN = 100005;
const int Blocks = 405;
int n, qk, a[MAXN], pre[MAXN], lst[MAXN], dp[MAXN], f[MAXN];
int sum[Blocks][MAXN], ans[Blocks], lz[Blocks], l[Blocks], r[Blocks], bl[MAXN];
inline void add(int &x, int y) { x += y; x = x >= mod ? x - mod : x; }
inline void sub(int &x, int y) { x -= y; x = x < 0 ? x + mod : x; }
inline void Rebuild(int x) {
for(int k = l[x]; k <= r[x]; ++k) sum[x][f[k]] = 0, f[k] += lz[x];
lz[x] = ans[x] = 0;
for(int k = l[x]; k <= r[x]; ++k) {
add(sum[x][f[k]], dp[k]);
if(f[k] <= qk) add(ans[x], dp[k]);
}
}
inline void Update(int k, int val) {
int x = bl[k];
sub(sum[x][f[k]], dp[k]);
if(f[k] <= qk) sub(ans[x], dp[k]);
f[k] += val;
add(sum[x][f[k]], dp[k]);
if(f[k] <= qk) add(ans[x], dp[k]);
}
inline void Modify(int x, int y, int val) {
int L = bl[x], R = bl[y];
if(L == R) {
Rebuild(L);
for(int k = x; k <= y; ++k)
Update(k, val);
}
else {
Rebuild(L);
for(int k = x; k <= r[L]; ++k) Update(k, val);
Rebuild(R);
for(int k = l[R]; k <= y; ++k) Update(k, val);
for(int i = L+1; i < R; ++i)
if(val == 1) {
int tmp = qk - (lz[i]++);
sub(ans[i], sum[i][tmp]);
}
else {
int tmp = qk - (--lz[i]);
add(ans[i], sum[i][tmp]);
}
}
}
inline int Query(int x) {
int re = 0;
Rebuild(bl[x]);
for(int k = l[bl[x]]; k <= x; ++k)
if(f[k] <= qk) add(re, dp[k]);
for(int i = 1; i < bl[x]; ++i) add(re, ans[i]);
return re;
}
int main() {
scanf("%d%d", &n, &qk);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
pre[i] = lst[a[i]];
lst[a[i]] = i;
}
dp[1] = 1;
int m = sqrt(n);
for(int i = 1; i <= n; ++i) {
bl[i] = (i-1)/m + 1;
r[bl[i]] = i;
if(!l[bl[i]])
l[bl[i]] = i;
}
for(int i = 1; i <= n; ++i) {
Modify(pre[i]+1, i, 1);
if(pre[i])
Modify(pre[pre[i]]+1, pre[i], -1);
dp[i+1] = Query(i);
}
printf("%d\n", dp[n+1]);
}

写加法减法的时候用问号语句600ms,用if语句1400ms。。


E. Legendary Tree

  • 时间限制:3 seconds
  • 内存限制:256 megabytes

This is an interactive problem.\it{This\ is\ an\ interactive\ problem.}This is an interactive problem.

题意

给出树的节点数n(≤500)n(\le 500)n(≤500),你的任务是确定树的结构。

你可以询问111111111111111次,每次查询&lt;{S},{T},v&gt;&lt;\{S\},\{T\},v&gt;<{S},{T},v>,格式如下

line 1:∣S∣line\ 1:|S|line 1:∣S∣

line 4:S1,S2,S3...S∣S∣line\ 4:S_1,S_2,S_3...S_{|S|}line 4:S1​,S2​,S3​...S∣S∣​

line 3:∣T∣line\ 3:|T|line 3:∣T∣

line 4:T1,T2,T3...T∣T∣line\ 4:T_1,T_2,T_3...T_{|T|}line 4:T1​,T2​,T3​...T∣T∣​

line 5:vline\ 5:vline 5:v

表示询问从∣S∣|S|∣S∣集的某个点经过vvv走到∣T∣|T|∣T∣集的某个点的简单路径条数。其中S⋂T=∅S\bigcap T=\varnothingS⋂T=∅

分析

先把1设为根

那么我们只要查询nnn次 &lt;{1},{2...n},i&gt;&lt;\{1\},\{2...n\},i&gt;<{1},{2...n},i> 就能得到iii的子树大小sz[i]sz[i]sz[i]。

我们的目标是找到所有个节点的父亲

显然父亲的szszsz比儿子大

我们把2~n的节点按szszsz排序

用一个vector存储到目前还没有找到父亲的点,这些点实际上可以看做叶节点,因为那些找到了父亲的点已经被我们从vector内删去。

按szszsz从小到大考虑,当前考虑到第iii个点,如果它有儿子,那么一定存在于vector中。如果iii是jjj的父亲,那么一定存在从1−&gt;i−&gt;j1-&gt;i-&gt;j1−>i−>j的路径,反之一定不存在(不可能有隔代的路径,因为我们是按szszsz从小到大考虑,隔代的情况不会出现 因为中间那一代szszsz小会被先考虑)。所以我们可以用一次查询&lt;{1},{S},i&gt;&lt;\{1\},\{S\},i&gt;<{1},{S},i>来判断叶节点集SSS内是否有iii的儿子。那么我们二分找到最左边的一个儿子,将它删去,并把它的父亲设为iii。这样一直做下去,就行了。一个点只会被删一次,查询log nlog\ nlog n次。

总查询次数是O(n+n logn)O(n+n\ logn)O(n+n logn)

时间复杂度是O(n2logn)O(n^2logn)O(n2logn)

#include<bits/stdc++.h>
using namespace std;
vector<int>S, T, vec;
#define pb push_back
const int MAXN = 505;
int n, sz[MAXN], c[MAXN], fa[MAXN];
inline int query(int x) {
printf("%d\n", S.size());
for(auto v:S) printf("%d ", v);
printf("\n%d\n", T.size());
for(auto v:T) printf("%d ", v);
printf("\n%d\n", x);
fflush(stdout);
int re; scanf("%d", &re);
return re;
}
inline bool chk(int x, int pos) {
T.clear();
for(int i = 0; i <= pos; ++i)
T.pb(vec[i]);
return query(x);
}
inline void getchild(int x) {
while(!vec.empty()) {
int l = 0, r = vec.size()-1, pos = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(chk(x, mid)) pos = mid, r = mid-1;
else l = mid+1;
}
if(~pos) {
fa[vec[pos]] = x;
swap(vec[pos], vec.back());
vec.pop_back();
}
else return;
}
}
inline bool cmp(int A, int B) { return sz[A] < sz[B]; }
int main() {
scanf("%d", &n);
S.pb(1);
for(int i = 2; i <= n; ++i) T.pb(i), c[i-1] = i;
for(int i = 2; i <= n; ++i) sz[i] = query(i);
sort(c + 1, c + n, cmp);
for(int i = 1; i < n; ++i) {
int x = c[i];
getchild(x);
vec.pb(x);
}
puts("ANSWER");
for(int i = 2; i <= n; ++i)
printf("%d %d\n", fa[i]?fa[i]:1, i);
}//最后自动fflush

这道题200组数据又是交互题很慢直接评测了5min。。。

Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1) 题解的更多相关文章

  1. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) 题解

    Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) 题目链接:https://codeforces.com/contest/1130 ...

  2. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1) C(二分+KMP)

    http://codeforces.com/contest/1129/problem/C #include<bits/stdc++.h> #define fi first #define ...

  3. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2) A - D2

    A. Be Positive 链接:http://codeforces.com/contest/1130/problem/A 题意: 给一段序列,这段序列每个数都除一个d(−1e3≤d≤1e3)除完后 ...

  4. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 2)

    A. Be Positive 题意:给出一个数组 每个树去除以d(d!=0)使得数组中大于0的数 大于ceil(n/2) 求任意d 思路:数据小 直接暴力就完事了 #include<bits/s ...

  5. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1)C. Morse Code

    题意:给你n个01字符,每次问你前缀的所有本质不同的子串,由摩斯密码组成的方案数和. 题解:离线处理,把字符建sam,通过topo序来dp计算每个节点表示的子串方案数的和.统计答案时,把n个字符挨个匹 ...

  6. Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1)

    A - Toy Train 很显然,一个站有多少个糖,那么就要从这个点运多少次.设第i个点有\(a_i\)个糖,那么就要转\(a_i-1\)圈,然后再走一段.很显然最后一段越小越好. 然后枚举起点后, ...

  7. Codeforces Round 542 (Div. 2)

    layout: post title: Codeforces Round 542 (Div. 2) author: "luowentaoaa" catalog: true tags ...

  8. Codeforces Round #182 (Div. 1)题解【ABCD】

    Codeforces Round #182 (Div. 1)题解 A题:Yaroslav and Sequence1 题意: 给你\(2*n+1\)个元素,你每次可以进行无数种操作,每次操作必须选择其 ...

  9. Codeforces Round #542 题解

    Codeforces Round #542 abstract I决策中的独立性, II联通块染色板子 IIIVoronoi diagram O(N^2 logN) VI环上距离分类讨论加取模,最值中的 ...

随机推荐

  1. NotePad++ 正则表达式 转

    https://gerardnico.com/ide/notepad/replace https://notepad-plus-plus.org/community/topic/16787/find- ...

  2. Tcp问题汇总

    一 TCP三次握手 PS:TCP协议中,主动发起请求的一端称为『客户端』,被动连接的一端称为『服务端』.不管是客户端还是服务端,TCP连接建立完后都能发送和接收数据. 起初,服务器和客户端都为CLOS ...

  3. java源码 --List、Set、Collection

    List和Set都是接口,它们继承与Collection.List是有序的队列,可以用重复的元素:而Set是数学概念中的集合,不能有重复的元素.List和Set都有它们各自的实现类. 为了方便,我们抽 ...

  4. SpringBoot使用thymeleaf的方式引用static中的静态资源

    当我们在开发网站时为了快速完成,避免不了使用第三方的框架文件.这样我们就得引用框架中的各种资源文件.那么,在springboot中通过 thymeleaf如何在html中使用static文件夹下的静态 ...

  5. [NOIP普及组2001]最大公约数和最小公倍数问题

    目录 链接 博客链接 题目链接 题目内容 题目描述 格式 输入 输出 数据 样例 输入 输出 说明 题目名称:最大公约数和最小公倍数问题 来源:2001年NOIP普及组 链接 博客链接 CSDN 洛谷 ...

  6. java之集合那些事

    集合概述: 集合和数组都可以保存多个对象,但是数组的长度不可变,集合可以保存数量变化的数据.java中的集合类主要由两个接口派生出,Collection和Map Collection接口和Iterat ...

  7. 方法引用(method reference)

    目录 方法引用(method reference) 1. 含义 2. 分类 3. 总结 方法引用(method reference) 1. 含义 方法引用实际上是 Lambda 表达式的一种语法糖. ...

  8. [Vue]vue中路由重定向redirect

    1.重定向的地址不需要接收参数 const routes = [ { path: '/', redirect: '/index'}, { path: '/index', component: inde ...

  9. 生成 excel 插件 Epplus

    最近做 .net core 项目 发现一个新的 生成excel 的插件 . 以前值用 aspose 或者 npio. 简介:Epplus是一个使用Open Office XML(Xlsx)文件格式,能 ...

  10. .net core +gogs + jenkins +docker自动化发布、部署

    1.首先,安装docker,不多bb 2.我们采用docker的方式安装jenkins,同时将宿主机的docker挂载到docker安装的jenkins里面,可能有点拗口.说白了就是 就是要让jenk ...