Codeforces Round #776 (Div. 3)

CodeForces - 1650D Twist the Permutation

给定你数组a:1 2 3 ... n,一共有n次操作,每次操作可以把\(a_i\)移到最左边,然后对\(i+1\)位以后不会产生影响,每次操作可以进行任意次,例如 :5 4 3 1 2 ,现在处于第三次操作,那么我只能在\(a_3\)位置上操作,操作一次后:

3 5 4 1 2,操作两次后:4 3 5 1 2,以此类推,现在给你操作完之后的数组a,让你计算出他在每个位置上的操作数分别是多少?

题解:思维+模拟

我们可以倒过来想,因为每一次操作不会对他后面的数造成影响,所以元素n现在的位置一定是最后一次操作操作若干次得到的,那么我们就得到了最后一次的操作数,根据这个操作数我们进行还原,还原得到的数组中n-1的位置一定是倒数第二次操作得到的,这样我们就得到了倒数第二次的操作数....以此类推

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int n, a[N], b[N];
int ans[N]; void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = n; i >= 1; --i)
{
int step = -1;
if (i != n)
{
for (int j = 1; j <= n; ++j)
a[j] = b[j];
}
for (int j = 1; j <= i; ++j)
if (a[j] == i)
{
if (j != i)
step = j;
else
step = 0;
break;
}
if (step == -1)
{
cout << -1 << endl;
return;
}
ans[i] = step;
for (int j = 1; j <= i; ++j)
{
int pos = (j - step + i) % i;
if (pos == 0)
pos += i;
b[pos] = a[j];
}
b[i] = i;
}
for (int i = 1; i <= n; ++i)
cout << ans[i] << " ";
cout << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}

CodeForces - 1650E Rescheduling the Exam

给你一张1-d长度的时间表,在这个时间表内安排了n场考试,你现在只能任意改变一场考试的时间,使得两场考试之间的休息时间u的最小值最大

题解:贪心+模拟

其实二分答案也能做,但是太难调了,直接放弃了,我们发现如果要使u变大,我们需要改变休息时间最短的两场考试\(a_i,a_{i-1}\)其中之一,那么假设我们改变\(a_i\)的时间,那么它可以插入的地方只有两个地方才有可能使得答案变大:

  1. 休息时间最长的两场考试中间,那么插入后他们之间的休息时间为:\((a_j-a_{j-1}-2)/2\)
  2. 插在最后一天\(d\)处,休息时间为:\(d-a[last]-1\),注意\(a[last]\)是会改变的

那么我们贪心在这两种插入中我们选择最大值,然后最大值再和改变后休息时间最短\(minn\)取\(min\)即可

那么我们已经考虑了改变\(a_i\)的情况,对于\(a_{i-1}\)只要\(i>1\)我们都可以按照上面的流程再走一遍,看一下u会不会更大

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int n, d;
int a[N]; int cal(int pos)
{
int pre = 0;
int minn = INF, maxx = -INF;
for (int i = 1; i <= n; ++i)
{
if (i != pos)
{
minn = min(minn, a[i] - a[pre] - 1);
maxx = max(maxx, a[i] - a[pre] - 1);
pre = i;
}
}
return min(minn, max((maxx - 1) / 2, d - a[pre] - 1));
} void solve()
{
cin >> n >> d;
for (int i = 1; i <= n; ++i)
cin >> a[i];
int minn = INF;
int pos = -1;
for (int i = 1; i <= n; ++i)
if (a[i] - a[i - 1] - 1 < minn)
{
pos = i;
minn = a[i] - a[i - 1] - 1;
}
int ans = -INF;
ans = max(ans, cal(pos));
if (pos > 1)
ans = max(ans, cal(pos - 1));
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}

CodeForces - 1650F Vitaly and Advanced Useless Algorithms

现在给你n个任务,每个任务都有截止时间,你需要将每个任务进程都完成100%,才算成功,又给定m种操作,每次操作给定\(e,t,p\),代表对于任务e,可以利用t时间将其进度增加p,每种操作只能用一次,求最后能否完成所有任务,如果能完成求出完成所有任务的最短用时,并将选择的操作以任意顺序输出

题解:01背包求方案数,感觉是一道好题目,下次记得复习

首先这是一个先明显的01背包求方案数的题目,因为存在截止时间,所以我们肯定要从截止时间短的任务开始做起,我们只需要对于每一个任务所对应的操作进行01背包,然后如果该任务完成的最短时间超过其给定的时间,那么说明后面的任务都完成不了了,如果能完成,那么剩余的时间我们可以分配给下一个任务,那么对于每次任务我们在dp时再记录方案即可

对于这道题,两个重点我们需要把握:

  1. 如何在一维滚动数组中记录方案数,我们可以开个vector[N],对于每次转移我们先将方案数转移,然后再在vector[]后面加上本次操作的id,\(pre[j] = pre[max(0ll, j - p)],\ \ \ \ pre[j].push\_back(id);\)
  2. 如何对所有操作数按照任务分类,同样可以利用vecrot,借助邻接表的思想进行分类
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 4e5 + 10; int n, m;
vector<array<int, 3>> v[N];
int a[N], f[N];
int dif[N];
vector<int> ans; void solve()
{
ans.clear();
cin >> n >> m;
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= n; ++i)
dif[i] = a[i] - a[i - 1];
for (int i = 1; i <= n; ++i)
v[i].clear();
for (int i = 1, e, t, p; i <= m; ++i)
{
cin >> e >> t >> p;
v[e].push_back({t, p, i});
}
for (int i = 1; i <= n; ++i)
{
vector<int> pre[101];
f[0] = 0;
for (int j = 1; j <= 105; ++j)
f[j] = INF;
for (auto &[t, p, id] : v[i])
{
for (int j = 100; j >= 0; --j)
{
if (f[j] > f[max(0ll, j - p)] + t)
{
f[j] = f[max(0ll, j - p)] + t;
pre[j] = pre[max(0ll, j - p)];
pre[j].push_back(id);
}
}
}
if (f[100] > dif[i])
{
cout << -1 << endl;
return;
}
dif[i + 1] += dif[i] - f[100];
for (auto id : pre[100])
ans.push_back(id);
}
cout << ans.size() << endl;
for (auto id : ans)
cout << id << " ";
cout << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}

CodeForces - 1650G Counting Shortcuts

给定一个无向图,没有自环和重边,给定起点st和终点ed,假设st到ed的最短距离为x,让你求出所有st到ed路径长度<=x+1的所有路径数(可以是简单路径,也可以不是简单路径)

题解:次短路和最短路求方案数 + 计数DP: 需要回顾复习

这是一道经典的最短路求方案数的问题,但同时我们只要再记录次短路的长度和方案数即可,我们可以在\(dijktra\)中对方案数进行记录和转移

现在解释一下\(dis[u][0/1]\):表示起点到u节点的最短距离(0)和次短距离(1)

同时我们在跑dij的时候将路径入队的同时需要分清楚这条路径是最短路还是次短路,我们可以定义结构体,在结构体中增加一个\(flag\)用来区分最短路和次短路

我们先来解释一下dp计数部分:

状态表示:\(f[u][0/1]\):代表从起点到u节点最短路径(0)的方案数,次短路(1)的方案数

状态属性:数量

状态转移:我们考虑四种情况

  1. \(dis[u][type]+w\)小于最短路\(dis[v][0]\),如果最短路已经被松弛过了,我们可以将其方案数和距离转移给次短距离,并将次短路入队,然后再将\(f[u][type]\)转移给最短路后入队;如果没有被松弛过,直接将\(f[u][type]\)转移给最短路后入队
  2. \(dis[u][type]+w\)等于最短路\(dis[v][0]\),该点最短路的方案数需要增加\(f[v][0] += f[u][type]\)
  3. \(dis[u][type]+w\)大于次短路\(dis[v][1]\),修改次短路后,对方案数进行转移\(f[v][1] = f[u][type]\),然后入队
  4. \(dis[u][type]+w\)等于次短路\(dis[v][1]\),该点次短路的方案需要增加\(f[v][1] += f[u][type]\)

那么对于答案输出部分:

如果\(f[ed][1]-f[ed][0]==1\),说明满足题目条件,答案为\(f[ed][0]+f[ed][1]\)

如果\(f[ed][1]-f[ed][0]!=1\), 不满足题目条件,答案为\(f[ed][0]\)

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int n, m;
vector<pii> g[N];
int st, ed;
int f[N][2], dis[N][2], vis[N][2];
struct node
{
int u, dis, flag;
bool operator<(const node &t) const
{
return dis > t.dis;
}
}; void dij(int st)
{
for (int i = 1; i <= n; ++i)
{
dis[i][0] = dis[i][1] = inf;
f[i][0] = f[i][1] = 0;
vis[i][0] = vis[i][1] = 0;
}
priority_queue<node> q;
q.push({st, 0, 0});
dis[st][0] = 0;
f[st][0] = 1;
while (q.size())
{
node t = q.top();
int u = t.u, type = t.flag;
q.pop();
if (vis[u][type])
continue;
vis[u][type] = 1;
for (auto &[v, w] : g[u])
{
if (dis[v][0] > dis[u][type] + w)
{
if (dis[v][0] != inf)
{
f[v][1] = f[v][0];
dis[v][1] = dis[v][0];
q.push({v, dis[v][1], 1});
}
f[v][0] = f[u][type];
dis[v][0] = dis[u][type] + w;
q.push({v, dis[v][0], 0});
}
else if (dis[v][0] == dis[u][type] + w)
f[v][0] = (f[v][0] + f[u][type]) % mod;
else if (dis[v][1] > dis[u][type] + w)
{
f[v][1] = f[u][type];
dis[v][1] = dis[u][type] + w;
q.push({v, dis[v][1], 1});
}
else if (dis[v][1] == dis[u][type] + w)
f[v][1] = (f[v][1] + f[u][type]) % mod;
}
}
} void solve()
{
cin >> n >> m;
cin >> st >> ed;
for (int i = 1; i <= n; ++i)
g[i].clear();
for (int i = 1, u, v; i <= m; ++i)
{
cin >> u >> v;
g[u].push_back({v, 1});
g[v].push_back({u, 1});
}
dij(st);
if (dis[ed][1] - dis[ed][0] == 1)
cout << (f[ed][0] + f[ed][1]) % mod << endl;
else
cout << f[ed][0] << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}

Codeforces Round #776 (Div的更多相关文章

  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 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...

  10. 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts

    题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...

随机推荐

  1. 使用vscode调试ros

    https://blog.csdn.net/u012254599/article/details/106143540/ CMakeLists.txt set(CMAKE_BUILD_TYPE &quo ...

  2. vscode + vim 快捷键

    多行编辑 按V选中行,按大写I即可进入编辑模式 撤销恢复 CTRL + z 撤销 CTRL + shift + z 恢复 代码自动对齐 Alt + shift + f

  3. UEFI引导安装UBUNUT

    1.引导方式一定要选UEFI,否则一些显卡驱动将不能安装 2.安装的时候,要在第四个界面,也就是选择覆盖安装还是保留双系统的那个界面,选择其他,一定要自己分区 3.分区: 4.一共5个重要分区: 1. ...

  4. Balanced Team

    https://vjudge.net/problem/CodeForces-1133C 题意:在数组中找出一段  每两个元素差值不大于5的这段元素个数的最大值. 1 #include <iost ...

  5. drag拖拽相关

    实际开发中会遇到一些和拖拽有关的问题 : 1.移动端不支持鼠标拖拽功能, 2.拖拽时会选中页面中的其他文字,解决办法: <div onSelectStart="return false ...

  6. GeoServer发布Oracle空间数据

    1. 概述 Oracle是常用的数据库,Oracle数据库包含空间数据库,可以在Oracle中进行空间数据的存储,更详细的信息可参考: 空间数据库 | Oracle 中国 GeoServer是常用的开 ...

  7. OSI网络7层模型,TCP/IP协议族

    ARP和RARP协议在OSI中属于数据链路层,在我们的认知里属于网络层,与IP在一层 OSI 7层模型比这个5层模型多了三层,5层模型熟悉的情况下,可以这么记多出的层:用表会输 应用层 表示层 会话层 ...

  8. cximage菜单(Load Jpeg Resource)

    // 菜单项 cximage->resource->Load Jpeg Resource //CxImage\demo\demo.cpp ON_COMMAND(ID_CXIMAGE_LOA ...

  9. video.js 注销上一个对象并重新初始化

    .dispose()没有用,不知道为什么. 后来我们为video绑定不同的id,还是随机数,每次初始化都用新video的id.并不建议这样做,但是我们也没有更好的办法了.

  10. mysql explain 查看sql语句执行计划概述

    mysql explain 查看sql语句执行计划概述 id:选择标识符select_type:表示查询的类型.table:输出结果集的表partitions:匹配的分区type:表示表的连接类型po ...