CodeForces1715

Crossmarket

解析:

题目大意

有一个 \(n \times m\) 的空间,Stanley 需要从左上角到右下角;Megan 则需要从左下角到右上角。两人可以耗费 \(1\) 能量到达相邻的格子。

为了加快到达的速度, Megan 会在经过的所有格子留下传送门,两人可以耗费 \(1\) 能量通过任意传送门通往任意有传送门的位置。

求两人均到达目的地耗费的最小总能量。


思路:

首先发现 Megan 不可能用传送门,因为这样折返最多让 Stanley 能够早点用传送门,但 Stanley 没走的路其实是让 Megan 走的,总能量并不优,正确的做法是 Megan 直接从左下,经过左上走到右上,而 Stanley 选择 \(n,m\) 中较大的边传送。

答案是 \(n-m-2\) (Megan 的能量)+ \(\min(n,m)\) (Stanley 的能量)。


code

#include <bits/stdc++.h>
using namespace std;
int n, m;
int solve ()
{
scanf ("%d%d", &n, &m);
if (n == 1 && m == 1) return 0;
if (n < m) swap (n, m);
return (n + m - 2) + m;
}
signed main()
{
int t = read ();
while (t--) printf ("%d\n", solve ());
return 0;
}

Beautiful Array

解析:

题目大意:

给定四个整数 \(n,k,b,s\),要求构造一个长度为 \(n\) 的序列 \(a\),使得 \(s=\sum\limits_{i=1}^na_i\) 且 \(b=\sum\limits_{i=1}^n\lfloor\frac{a_i}{k}\rfloor\)(\(a_i\) 必须为非负整数)。如果有多组解,输出任意一组解。对于无解的情况,输出 -1


思路:

大力构造,考虑总和 \(s\) 能凑出来的最大的 \(b\) 其实是 \(\frac{s}{k}\) ,感性理解就是我前面 \(n-1\) 个 \(a_i\) 都取 \(k\),最后剩了多少都给 \(a_n\),可以证明不存在更优的构造方案。

总和 \(s\) 可以构造的最小值可以类似考虑,我先给 \(n\) 个 \(a_i\) 都分 \(k-1\),那剩下的数不管放哪都会造成贡献了,那直接随便找一个放在一起就行了,因为我需要尽量不破坏其他 \(k-1\),可以证明这样凑出来的是最小的。

考虑现在判断了无解,构造方案可以参考最小值的构造,我先给 \(a_1\) 分 \(b\times k\),剩下的每次按照 \(k-1\) 分给 \(1-n\) 所有数,直到分完为止。


code:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int INF = 0x3f3f3f3f;
inline int read ()
{
int x = 0, f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
return x * f;
}
int n, k, b, s;
void solve ()
{
n = read (), k = read (), b = read (), s = read ();
int r = s / k, l = 0, sum = 0;
for (int i = 1; i < n; i++) sum += k - 1;
l = (s - sum) / k;
if (b < l || b > r) { printf ("-1\n"); return ; }
printf ("%lld ", min (s, k * (b + 1) - 1));
s -= min (s, k * (b + 1) - 1);
for (int i = 2; i <= n; i++)
{
if (s >= k - 1) { printf ("%lld ", k - 1); s -= (k - 1); }
else { printf ("%lld ", s); s -= s; }
}
printf ("\n");
}
signed main()
{
int t = read ();
while (t--) solve ();
return 0;
}

Monoblock

解析:

题目大意

我们定义连续连续极长且都是一个相同的数的子段被称为一个“块”。一个序列的连续极长的块的个数表示为 \(g(1,n)\)。

给定一个长度 \(n\) 的序列和 \(m\) 次询问。对于每次询问,有两个数 \(i,x\),先将 \(a_i\) 改为 \(x\),然后输出 \(\sum\limits_{l=1}^n\sum\limits_{r=l}^ng(l,r)\),其中 \(g(l,r)\) 表示 \(a_{l\sim r}\) 的“块”数。


思路:

诈骗题,第一眼发现什么数据结构都不能很好维护,就去看D了,切了D回来也秒了,事实证明这是个错误的决定(如果先写D排名能提好几百)。

首先观察到可以数组直接统计维护。

首先注意到一个序列的块的个数实际上等价于元素个数-有多少个数与前一个数的值相同,前者又等价于序列长度,可以直接维护,后者相当于考虑先找出来整个序列这样的数出现的位置,设其中一个数 \(a_i\) 和 \(a_{i-1}\) 值相同,那么包括这两个元素的子序列都会有一个 \(-1\) 的贡献,这样的子序列要求左端点 \(l\) 在 \(l\in[1,i-1]\),右端点 \(r\) 在 \(r\in[i,n]\) 之间,这样的子序列的个数有 \((i-1)\times(n-i+1)\) 个。

原问题转化为 \(\sum\text{所有子序列长度}-\sum{\text{所有贡献}}\),可以分开维护,前者直接 \(\mathcal O(1)\) 算,后者开个数组维护每个位置对答案的贡献是 \(0\) 还是 \(-(i-1)\times (n-i+1)\),单点改就直接改当前位置的数组值就行。

然后随便记个 \(sum\) 就解决了。


code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
typedef pair <int, int> pii;
inline int read ()
{
int x = 0, f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
return x * f;
}
int n, q;
int a[N];
int c[N], sum, sum2;
void solve (int x) { if (a[x] == a[x - 1]) c[x] = (x - 1) * (n - x + 1); else c[x] = 0; }
signed main()
{
n = read (), q = read ();
for (int i = 1; i <= n; i++) a[i] = read ();
for (int i = 2; i <= n; i++) solve (i);
for (int i = 1; i <= n; i++) sum += c[i], sum2 += (1 + i) * i / 2;
while (q--)
{
int x = read (), y = read ();
a[x] = y;
sum -= c[x]; sum -= c[x + 1];
solve (x), solve (x + 1);
sum += c[x]; sum += c[x + 1];
printf ("%lld\n", sum2 - sum);
}
return 0;
}

2+ doors

解析:

题目大意:

Narrator有一个长度为 \(n\) 的整数数组 \(a\) ,但是他只会告诉你 \(n\) 的大小和 \(q\) 个要求,每个要求包括三个整数 \(i,j,x\) ,要求满足 \(a_i\mid a_j = x\),其中 \(|\) 表示按位或运算

找到满足所有要求的字典序最小的数组 \(a\)。数据保证有解。


思路:

大套路题,首先套路的发现每一个二进制位互补影响,可以分开考虑,原问题变成给你 \(q\) 个限制,每个限制要求 \(a_i|a_j\in{0,1}\)。

考虑字典序最小,我们需要让尽量前面的数分配 \(0\) 这样一定最优,我们考虑跟 \(a_1\) 有关的 \(q_1\) 个限制,如果 \(\exist i,j|(a_1|a_i=1,a_1|a_j=1\and a_i|a_j=0)\),那么必有 \(a_i,a_j\) 为 \(0\),\(a_1\) 为 \(1\),否则让 \(a_1=0\),\(\forall i|(a_1|a_i=0)\),令 \(a_i=1\) 一定最优。

那么考虑先把当前二进制位满足 \(a_i|a_j=0\) 的 \(i,j\) 强制为 \(0\),然后从 for 1 -> n 检索每一个 \(i\),如果 \(\exist j,j\in[i,n]\and a_j=0\),那么 \(a_i=1\),否则让有条件限制的都取1即可。

时间复杂度 \(\mathcal O(V(n+q))\),其中 \(V\) 取到 \(\log x\)。


code:

#include <bits/stdc++.h>
#define int long long
#define eb emplace_back
#define fi first
#define se second
#define mk make_pair
using namespace std;
const int N = 2e5 + 10;
const int INF = LLONG_MAX;
typedef pair <int, int> pii;
inline int read ()
{
int x = 0, f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar (); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar (); }
return x * f;
}
int n, m;
vector <pii> vec[N];
struct node {
int x, y, k;
} s[N];
int a[32][N];
signed main()
{
n = read (), m = read (); int mn = INF, mx = 0;
for (int i = 1; i <= m; i++)
{
s[i].x = read (), s[i].y = read (), s[i].k = read ();
if (s[i].x > s[i].y) swap (s[i].x, s[i].y);
vec[s[i].x].eb (mk(s[i].y, s[i].k));
mx = max (mx, s[i].k);
}
if (mx == 0) { while (n--) printf ("0 "); return 0; } // 场上最终挂掉的特判,挂因是0之间忘加空格了
memset (a, -1, sizeof (a));
for (int i = 31; i >= 0; i--)
{
for (int j = 1; j <= m; j++)
{
if (!((s[j].k >> i) & 1)) a[i][s[j].x] = 0, a[i][s[j].y] = 0;
if (s[j].x == s[j].y) a[i][s[j].x] = (s[j].k >> i) & 1;
}
for (int j = 1; j <= n; j++)
{
if (a[i][j] != -1)
{
if (a[i][j] == 0)
for (int k = 0; k < vec[j].size (); k++)
if (((vec[j][k].se >> i) & 1) == 1) a[i][vec[j][k].fi] = 1;
continue;
}
for (int k = 0; k < vec[j].size (); k++)
if (a[i][vec[j][k].fi] == 0 && ((vec[j][k].se >> i) & 1) == 1) { a[i][j] = 1; break; }
if (a[i][j] == 1) continue;
a[i][j] = 0;
for (int k = 0; k < vec[j].size (); k++)
if (((vec[j][k].se >> i) & 1) == 1) a[i][vec[j][k].fi] = 1;
}
}
for (int i = 1; i <= n; i++)
{
int sum = 0;
for (int j = 31; j >= 0; j--) sum += (a[j][i] << j);
printf ("%lld ", sum);
}
return 0;
}

Long Way Home

解析:

题目大意:

有 \(n\) 座城市,城市间有 \(m\) 条双向道路,通过第 \(i\) 条道路需要花费 \(w_i\) 的时间,任意两个城市之间都有航班,乘坐城市 \(u\) 和 \(v\) 之间的航班需要花费 \((u-v)^2\) 的时间,但最多乘坐 \(k\) 次航班。

现在请对于任意城市 \(i(1 \le i \le n)\),求出从城市 \(1\) 出发,到达城市 \(i\) 所需要的最短时间。


思路:

大力 dp+dijkstra,场上想到了怎么设 dp 状态,但碍于时间没想出来,或许也是板子不熟吧,按理讲应该能一眼切的。

发现 \((u-v)^2\) 是斜率优化的板子,而 \(k\) 实际上就是一个常数,这告诉我们只需要做 \(k\) 次 \(dp\)。

我们考虑设 \(dp_{i,j}\) 表示从 \(1\) 到 \(i\) 飞了 \(j\) 次的最小距离,那么有:

\[dp_{i,j}=\min_{k=1}^n dp_{k,j-1}+(k-i)^2
\]

把这个东西化简一下:

\[dp_{i,j}=\min_{k=1}^n dp_{k,j-1}+k^2-2ik+i^2\\
dp_{i,j}-i^2=\min_{k=1}^n dp_{k,j-1}+k^2-2ik
\]

那就是个斜率优化板子,我们考虑设 \(-2k\) 为 \(k\),\(k^2+dp_{k,j-1}\) 为 \(b\),那么维护一下下凸壳即可。

每次乘坐完飞机都跑一个dijkstra更新一下即可。


code:

#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mk make_pair
using namespace std;
const int N = 1e5 + 10;
const int K = 20 + 10;
const int INF = 0x3f3f3f3f;
typedef pair <int, int> pii;
inline int read ( )
{
int x = 0, f = 1;
char ch = getchar ( );
while (ch < '0' || ch > '9') {if (ch == '-') f = - 1; ch = getchar ( );}
while (ch >= '0' && ch <='9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar ( );}
return x * f;
}
int n, m, k;
struct edge {
int ver, nxt, val;
} e[N << 1];
int head[N], tot;
void add_edge (int u, int v, int w) { e[++tot] = (edge) {v, head[u], w}; head[u] = tot; }
int dp[K][N];
bool vis[N];
int h, t;
struct node {
int k, b, i;
double x, y;
} l[N];
inline double calc(node x, node y) { return double(y.b - x.b) / double(x.k - y.k); }
void dijkstra (int s, int x)
{
priority_queue <pii> que;
memset (vis, 0, sizeof (vis));
for (int i = 1; i <= n; i++) if (dp[x][i] != INF) que.push (mk (-dp[x][i], i));
while (!que.empty ())
{
int u = que.top ().second; que.pop ();
if(vis[u]) continue;
vis[u] = true;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].ver;
if (dp[x][v] > dp[x][u] + e[i].val)
{
dp[x][v] = dp[x][u] + e[i].val;
que.push (mk (-dp[x][v], v));
}
}
}
}
signed main()
{
n = read (), m = read (), k = read ();
for (int i = 1; i <= m; i++)
{
int u = read (), v = read (), w = read ();
add_edge (u, v, w);
add_edge (v, u, w);
}
memset (dp[0], 0x3f, sizeof (dp[0]));
dp[0][1] = 0;
for (int s = 0; s <= k; s++)
{
if (s)
{
h = 1; t = 0;
for (int i = 1; i <= n; i++)
{
if (dp[s - 1][i] == INF) continue;
node now = (node) { -2 * i, i * i + dp[s - 1][i], i, -INF, INF};
while (h <= t && calc (l[t], now) <= l[t].x) t--;
if (h <= t) l[t].y = now.x = calc (l[t], now);
l[++t] = now;
}
for (int i = 2; i <= n; i++)
{
while (h <= t && l[h].y < i) h++;
int k = l[h].i;
dp[s][i] = dp[s - 1][k] + (k - i) * (k - i);
}
for (int i = 1; i <= n; i++) dp[s][i] = min (dp[s - 1][i], dp[s][i]);
}
dijkstra (1, s);
}
for (int i = 1; i <= n; i++) printf ("%lld ", dp[k][i]);
return 0;
}

6

解析:

题目大意:


思路:

交互&人类智慧题,不会,咕了


code:


Codeforces Round #816 (Div. 2)/CodeForces1715的更多相关文章

  1. Codeforces Round #366 (Div. 2) ABC

    Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...

  2. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  3. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  4. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  5. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  6. Codeforces Round #262 (Div. 2) 1003

    Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...

  7. Codeforces Round #262 (Div. 2) 1004

    Codeforces Round #262 (Div. 2) 1004 D. Little Victor and Set time limit per test 1 second memory lim ...

  8. Codeforces Round #371 (Div. 1)

    A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给 ...

  9. Codeforces Round #268 (Div. 2) ABCD

    CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...

随机推荐

  1. 上传代码到GitHub仓库

    上传代码到GitHub仓库 准备工作 意思是自从 21 年 8 月 13 后不再支持用户名密码的方式验证了,需要创建个人访问令牌(personal access token). 这里就不多说了 Git ...

  2. 简单创建一个SpringCloud2021.0.3项目(三)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上俩篇教程 3. Gateway集成sentinel,网关层做熔断降级 1. 超时熔断降级 2. 异常熔断 3. 集成sentine ...

  3. Java基础——01

    今日学习 2020-2-27 Java多态 多态性格式 /* 代码中体现多态性 其实就是一句话:父类指向子类对象 格式: 父类名称 对象名= new 子类名称(): 或者 接口名称 对象名 = new ...

  4. token总结

    token 总结 1. token 和SessionID 的区别 Token机制相对于Cookie机制又有什么好处呢? 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的 ...

  5. EntityFrameworkCore 模型自动更新(下)

    话题 上一篇我们讨论到获取将要执行的迁移操作,到这一步为止,针对所有数据库都通用,在此之后需要生成SQL脚本对于不同数据库将有不同差异,我们一起来瞅一瞅 SQLite脚本生成差异 在上一篇拿到的迁移操 ...

  6. JavaWeb核心篇(2)——Request和Response

    JavaWeb核心篇(2)--Request和Response 上篇文章中提及到了Servlet,在Servlet中我们主要继承了HTTPServlet类,在HTTPServlet类中我们会接触到两个 ...

  7. Typora破解下载

    Typora破解下载 文章指路

  8. Q准则涡识别方法

    Q准则(Q Criterion)在涡识别中计算效率高,效果也不错,是一种常用的涡提取/识别方法. 了解Q准则需要从速度梯度张量入手,而速度梯度张量可以分解成两部分 \[\frac{\partial u ...

  9. 不懂 Kubernetes 实现云原生是什么体验?

    云原生的本质和最终效果 要明白什么是云原生,就要先弄明白云计算是什么有什么问题,云计算将计算资源.网络.存储等基础设施统一管理,通过资源规模化和自动化管理,实现降低资源的成本和提高资源的管理效率,云计 ...

  10. Git将本地仓库上传到github

    这里采用简单的描述,提供两种方式: 一.连接本地文件夹和远程仓库 1.使用pull--拉取github项目文件 (1)进入到自己要上传的文件夹内部,然后git bash here (2)输入命令 gi ...