A - 多边形与圆

题目链接

题意

给出一个多边形的坐标和圆的半径, 多边形可以在圆内滚动, 问点 1 在成为转动中心到下一次成为转动中心的过程中经过的路程长度.

题解

枚举点 2 - n 成为转动中心的情况下点 1 的路程.

view code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++) const int maxn = 1e2 + 5; int n, r;
double x[maxn], y[maxn], res; double dis(int i, int j) {
return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
// 这里应该用 atan2() 的
double aatan(int i, int j) {
if (x[i] == x[j]) {
if (y[i] > y[j]) return M_PI / 2;
return 3 * M_PI / 2;
}
return atan((y[i] - y[j]) / (x[i] - x[j]));
}
double alp(int i) {
double r = aatan(i, i - 1) - aatan(i, i + 1);
while (r < 0) r += M_PI;
while (r > M_PI) r -= M_PI;
return r;
} int main() {
cin >> n >> r;
inc(i, 1, n) cin >> x[i] >> y[i];
x[n + 1] = x[1], y[n + 1] = y[1];
inc(i, 1, n - 1) {
double d = dis(i, i + 1), d2 = dis(i + 1, i + 2), p = dis(1, i + 1);
double a = asin(d / 2 / r), a2 = asin(d2 / 2 / r);
res += (M_PI - a - a2 - alp(i + 1)) * p;
}
printf("%.12f\n", res);
}

 

B - 子串翻转

题目链接

题意

给出一个长度为 n 的字符串. 有 q 组操作, 一种是选择长度为 m 的区间 \([x_i, x_i + m - 1]\) 翻转, 一种是查询串上某一位置的字符. 每次翻转操作的起始坐标 \(x_i\) 是严格不减的. n ≤ 1e6, q ≤ 1e6.

题解

根据操作坐标的单调性, 使用滑动窗口维护被翻转的区间. 滑动窗口是一段长度为 m 的区间, 用 std::deque 保存内部元素, 它会从左往右扫描一遍区间, 遇到翻转操作时, 打上翻转标记(或取消翻转标记)而不实际改变内部元素. 处于翻转状态时, 移动滑动窗口, 本来要弹出队首元素, 但实际上该元素在队尾, 所以执行pop_back(); 本来要往队尾加入元素, 但该区间是翻转状态, 所以应加入队首以正确应对查询. 时间复杂度 O(n).

view code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++) const int maxn = 1e6 + 5; int n, m, q, x, y, f, top;
char a[maxn];
deque<char> deq; int main() {
scanf("%d %d %d", &n, &m, &q);
scanf("%s", a + 1);
inc(i, 1, m) deq.push_back(a[i]);
top = 1;
while (q--) {
scanf("%d %d", &x, &y);
if (x == 1) {
while (top < y) {
if (f) {
a[top] = deq.back();
deq.pop_back();
deq.push_front(a[top + m]);
} else {
a[top] = deq.front();
deq.pop_front();
deq.push_back(a[top + m]);
}
top++;
}
f = 1 - f;
} else {
if (y >= top && y < top + m) {
if (f)
printf("%c", deq[m - 1 - (y - top)]);
else
printf("%c", deq[y - top]);
} else
printf("%c", a[y]);
}
}
printf("\n");
}

 

C - 圆桌聚餐

题目链接

题意

A 国人与 B 国人在一张有 n 个位置的圆桌上吃饭, A 国人不会坐在旁边有人的位置, B 国人不会坐在距离 2 以内有人的位置. 刚开始圆桌上没有人, 接下来会有 p / (p + q) 的概率走进一个 A 国人, q / (p + q) 的概率走进一个 B 国人; 他会随机选择一个位置, 如果不符合他的要求就直接离开. 问最后不能再容纳人时人数的期望, 对 998244353 取模. n ≤ 3e5, 0 ≤ p, q < 998244353.

题解

首先第一个人坐下时不受任何限制, 且每个人坐下后是无差别的. 所以问题变成考虑剩下的 n - 1 个连续的位置能容纳多少人. 定义 dp[i] 为连续 i 个位置能容纳人的期望, p 不为 0 时有 dp[1] = dp[2] = 0, dp[3] = dp[4] = 1(p 为 0 时dp[3] = dp[4] = 0), 状态转移时枚举分隔位置即可. 推导出

\[dp[j] = \frac{p × \sum_{i=2}^{j-1}{(dp[i - 1] + dp[j - i])} + q × \sum_{i=3}^{j-2}{(dp[i - 1] + dp[j - i])}} { p × (j - 2) + q × (j - 4) } + 1 = \frac{2p × sdp[j - 2] + 2q × sdp[j - 3]} {p × (j - 2) + q × (j - 4)} + 1
\]

其中 sdp[] 是 dp[] 的前缀和

view code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++) const int maxn = 3e5 + 5;
const int mod = 998244353; ll dp[maxn], s[maxn];
int n;
ll p, q; inline ll ksm(ll a, ll n) {
ll r = 1;
while (n) {
if (n & 1) r = r * a % mod;
a = a * a % mod;
n >>= 1;
}
return r;
} int main() {
scanf("%d %lld %lld", &n, &p, &q);
if (p) dp[3] = dp[4] = s[3] = 1, s[4] = 2;
inc(i, 5, n - 1) {
dp[i] = ((2 * p * s[i - 2] + 2 * q * s[i - 3]) % mod *
ksm((p * (i - 2) + q * (i - 4)) % mod, mod - 2LL) +
1) %
mod;
s[i] = (s[i - 1] + dp[i]) % mod;
}
printf("%lld\n", (dp[n - 1] + 1) % mod);
}

 

D - 突击检查

题目链接

题意

有一个具有 n 个点的树, 给出每个点的度数. 已知有 X 个点被打上了标记, 记被打标记的点之间形成的联通块数为 x, 求 \(E(x^2)\). n ≤ 2e6.

题解

只考虑被打标记的点及其之间的边, 得到 \(x = 点数 - 边数\). 则 \(x^2 = 点数^2 - 2 × 点数 × 边数 + 边数^2\), 边数的期望由每一条边的贡献得到, 即

\[\frac{(n - 1) × C_{n-2}^{X-2}}{C_{n}^{X}}
\]

而边数的平方是枚举所有的边对, 这个时候要分类讨论选出的两条边的共同点个数是 0, 1 还是 2, 题解定义了一个 \(adj = \sum_{i=1}^{n}du[i] × (du[i] - 1)\), 它的意义是对于每个点选出两条不同的边对数. 最后得到是

\[\frac { [(n - 1) × (n - 2) - adj] × C_{n-4}^{X-4} + adj × C_{n-3}^{X-3} + (n - 1) × C_{n-2}^{X-2} }{C_n^X}
\]

这题调了半天发现 2000000 少打了一个 0.

view code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++) const int maxn = 2e6 + 5;
const int mod = 998244353; ll du[maxn], adj, res;
ll n, x; inline ll ksm(ll _a, ll _n) {
ll _r = 1;
while (_n) {
if (_n & 1) _r = _r * _a % mod;
_a = _a * _a % mod;
_n >>= 1;
}
return _r;
}
ll fac[maxn];
inline void getfac() {
fac[0] = 1;
inc(i, 1, 2000000) fac[i] = fac[i - 1] * i % mod;
}
inline ll C(ll _n, ll _m) {
if (_n < 0 || _m < 0 || _n < _m) return 0;
return fac[_n] * ksm(fac[_n - _m], mod - 2LL) % mod *
ksm(fac[_m], mod - 2LL) % mod;
}
inline ll inv(ll _n) { return ksm(_n, mod - 2LL); } int main() {
getfac();
scanf("%lld %lld", &n, &x);
inc(i, 1, n) {
scanf("%lld", &du[i]);
adj = (adj + du[i] * (du[i] - 1)) % mod;
}
res = (x * x % mod -
(2 * x - 1) * (n - 1) % mod * C(n - 2, x - 2) % mod * inv(C(n, x)) %
mod +
((n - 1) * (n - 2) % mod + mod - adj) % mod * C(n - 4, x - 4) % mod *
inv(C(n, x)) % mod +
adj * C(n - 3, x - 3) % mod * inv(C(n, x)) % mod + mod) %
mod;
printf("%lld\n", res);
}

 

牛客挑战赛38 (A - D)的更多相关文章

  1. 牛客练习赛38 D 出题人的手环

    链接 [https://ac.nowcoder.com/acm/contest/358/D] 题意 链接:https://ac.nowcoder.com/acm/contest/358/D 来源:牛客 ...

  2. 牛客练习赛38 D 题 出题人的手环 (离散化+树状数组求逆序对+前缀和)

    链接:https://ac.nowcoder.com/acm/contest/358/D来源:牛客网 出题人的手环 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...

  3. 出题人的女装(牛客练习赛38题B) (概率+分式运算)

    链接:https://ac.nowcoder.com/acm/contest/358/B来源:牛客网 出题人的女装 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...

  4. 牛客挑战赛 39 牛牛与序列 隔板法 容斥 dp

    LINK:牛牛与序列 (牛客div1的E题怎么这么水... 还没D难. 定义一个序列合法 当且仅当存在一个位置i满足 $a_i>a_,a_j<a_$且对于所有的位置i,$1 \leq a_ ...

  5. 牛客挑战赛 30 A 小G数数

    题目链接:https://ac.nowcoder.com/acm/contest/375/A 分析:我写的时候竟然把它当成了DP....... 还建了个结构体DP数组,保存一二位,不知道当时脑子在抽啥 ...

  6. 良心送分题(牛客挑战赛35E+虚树+最短路)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 给你一棵树,然后把这棵树复制\(k\)次,然后再添加\(m\)条边,然后给你起点和终点,问你起点到终点的最短路. 思路 由于将树复制\(k\) ...

  7. Luogu5611 Ynoi2013 D2T2/牛客挑战赛32F 最大子段和 分块、分治

    传送门 之前一直咕着的,因为一些特殊的原因把这道题更掉算了-- 有一个对值域莫队+线段树的做法,复杂度\(O(n\sqrt{n} \log n)\)然而牛客机子实在太慢了没有希望(Luogu上精细实现 ...

  8. 牛客挑战赛30 小G砍树 树形dp

    小G砍树 dfs两次, dp出每个点作为最后一个点的方案数. #include<bits/stdc++.h> #define LL long long #define fi first # ...

  9. 牛客挑战赛30D 小A的昆特牌(组合数学)

    题面 传送门 题解 很容易写出一个暴力 \[\sum_{i=l}^r {i+n-1\choose n-1}{s-i+m\choose m}\] 即枚举选了多少个步兵,然后用插板法算出方案数 我们对这个 ...

随机推荐

  1. C#可空类型知多少

    在项目中我们经常会遇到可为空类型,那么到底什么是可为空类型呢?下面我们将从4个方面为大家剖析. 1.可空类型基础知识 顾名思义,可空类型指的就是某个对象类型可以为空,同时也是System.Nullab ...

  2. Zabbix自动发现并监控磁盘IO、报警

    本文转载自: https://www.93bok.com 引言 Zabbix并没有提供模板来监控磁盘的IO性能,所以我们需要自己来创建一个,由于一台服务器中磁盘众多,如果只有一两台可以手动添加,但服务 ...

  3. 图解MySQL索引(上)—MySQL有中“8种”索引?

    关于MySQL索引相关的内容,一直是一个让人头疼的问题,尤其是对于初学者来说.笔者曾在很长一段时间内深陷其中,无法分清"覆盖索引,辅助索引,唯一索引,Hash索引,B-Tree索引--&qu ...

  4. docker 学习(四)

    1.Dockerfile简介 1)什么是Dockerfile Dockerfile是一个包含用于组合映像的命令的文本文档.可以使用在命令行中调用任何命令. Docker通过读取Dockerfile中的 ...

  5. NLP(二十四)利用ALBERT实现命名实体识别

      本文将会介绍如何利用ALBERT来实现命名实体识别.如果有对命名实体识别不清楚的读者,请参考笔者的文章NLP入门(四)命名实体识别(NER) .   本文的项目结构如下:   其中,albert_ ...

  6. 浅析js中的堆和栈

    这里先说两个概念:1.堆(heap)2.栈(stack)堆 是堆内存的简称.栈 是栈内存的简称.说到堆栈,我们讲的就是内存的使用和分配了,没有寄存器的事,也没有硬盘的事.各种语言在处理堆栈的原理上都大 ...

  7. 5.创建app、创建user表、配置media、数据迁移

    目录 user模块User表 创建user模块 创建User表对应的model:user/models.py 注册user模块,配置User表:dev.py 配置media 数据库迁移 user模块U ...

  8. Python 之装饰器

    Python 的装饰器可谓是提高开发效率的一大利器.然而初学装饰器的时候感觉很难理解,因为除了 Python 之外没听说哪个语言有这种东西. 而且网上看的很多解释看似容易理解,但只能很快理解了装饰器能 ...

  9. Python第一周作业

    import turtle turtle.color('black','red') turtle.pensize(10) turtle.begin_fill() for i in range(5): ...

  10. 【转】不怕难之BlockingQueue及其实现

    1. 前言 BlockingQueue即阻塞队列,它是基于ReentrantLock,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所 ...