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. java基础(数组、面向抽象编程、static、异常)

    数组 相同的数据类型的数据集合 按照一定的先后次序排列组合 通过下标来访问他们 声明---创建 建议 String[] a; String a [];//c 和c++才有不专业 String [] a ...

  2. JavaScript数组的方法大全(最新)

    JavaScript数组方法大全 趁着有时间,总结了下数组所有的属性和方法,记录博客,便于后续使用 array.at() at方法,用于获取数组中,对应索引位置的值,不能修改. 语法:array.at ...

  3. 什么是MES(Manufacturing Execution System)

    "本文仅代表个人观点" 本文档将提供一个高层次的概述,以帮助阐明什么是MES,并触及通常被归为MES的周边领域. 整体情况 制造执行系统或MES软件是旨在帮助公司管理其制造过程的工 ...

  4. forEach、for in 、 for of三者的区别

    1.for 原始的遍历: 其实除了这三种方法以外还有一种最原始的遍历,自Javascript诞生起就一直用的 就是for循环,它用来遍历数组 var arr = [1,2,3,4] for(var i ...

  5. vue 组件通信方式 ,父子、隔代、兄弟 三类通信,六种方法

    (1)props / $emit 适用 父子组件通信 (2) ref 与 $parent / $children 适用 父子组件通信 (3)$attrs / $listeners 适用于 隔代组件通信 ...

  6. pycharm取消代码长度的竖线

  7. CF207C

    前言 学习 zzd 博客( 这题超级没有素质. 连个题解都搜不到. 好不容易搜到一个. 看了一下是 pascal. 不过还好我有办法. 树剖做 \(k\) 级祖先. 十万的俩老哥飘过. 三百毫秒优异成 ...

  8. VOLO论文笔记

    Outlook Attention 设给定输入为 \(X \in R^{H \times W \times C}\), 首先经过两个线性映射得到两个输出A 和 V,A叫做outlook weight ...

  9. 右键无法新建word文件怎么办?

      电脑用久了,总会出现奇奇怪怪的问题.   我最近遇到一个问题:鼠标右键无法新建word文件.如何解决此问题呢?   刚开始,我忍了.解决方法为:把word图标固定到任务栏,就好了呗,需要用的时候, ...

  10. 字符类型(char)

    字符类型(char) 基本介绍 字符类型可以表示`单个字符`,字符类型是char,char是两个字节(可以存放汉字),多个字符我们用字符串String(我们后面详细讲解String) 案例演示 //演 ...