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. Taurus.MVC WebAPI 入门开发教程6:全局控制器DefaultController与全局事件。

    系列目录 1.Taurus.MVC WebAPI  入门开发教程1:框架下载环境配置与运行. 2.Taurus.MVC WebAPI 入门开发教程2:添加控制器输出Hello World. 3.Tau ...

  2. eclipse小技巧---快速复制全类名

    选中类名,并鼠标右键选择 Copy qualified name

  3. virsh edit 很慢 的bug

    创建虚拟机,发现virsh edit很慢. strace的结果: 09:26:03 close(10) = -1 EBADF (Bad file descriptor)09:26:03 close(1 ...

  4. linux 旁路掉协议栈的处理点

    对于协议栈的发展,目前有三种处理趋势,一种是类似于使用dpdk的方式,然后将协议栈放到用户态来做,做得比较好的一般都是以bsd的协议栈为底子,可以参考的是腾讯开源的的方案,另外一种是,继续放在内核,但 ...

  5. PlayCover for mac-Mac 上全屏运行 iOS 应用程序

    前言 如何在Mac电脑运行ios应用呢?PlayCover for Mac一款彻底解放苹果电脑的iOS软件安装工具,无需付费,操作简单,可以安装ipa文件,可以通过鼠标.键盘和控制器 在Mac上全屏运 ...

  6. 【Java】学习路径50-线程死锁问题

    生活化的例子:比如说有两个人,一把刀和一把叉子: 第一个人先需要一把刀,然后还需要一把叉子: 第二个人先需要一把叉子,然后还需要一把刀. 我们理想的情况是:一个人拿着刀,然后再拿到叉子,把事情做完,然 ...

  7. 端口安全 | DHCP snooping

    1.端口安全用于防止mac地址的欺骗.mac地址泛洪攻击.主要思想就是在交换机的端口下通过手工或者自动绑定mac地址,这就就只能是绑定的mac地址能够通过. 2.通过静态的端口绑定:将mac地址手工静 ...

  8. git revert总结

    git revert git revert 是一种创建一次新的commit 来回退某次或某几次commit的一种方式 命令 // 创建一个新的commit,这个commit会删除(下面)commit- ...

  9. 【读书笔记】C#高级编程 第二十五章 事务处理

    (一)简介 事务的主要特征是,任务要么全部完成,要么都不完成. (二)概述 事务由事务管理器来管理和协调.每个影响事务结果的资源都由一个资源管理器来管理.事务管理器与资源管理器通信,以定义事务的结果. ...

  10. 如何在 Jenkins CI/CD 流水线中保护密钥?

    CI/CD 流水线是 DevOps 团队软件交付过程的基本组成部分.该流水线利用自动化和持续监控来实现软件的无缝交付.通过持续自动化,确保 CI/CD 流水线每一步的安全性非常重要.在流水线的各个阶段 ...