2019牛客多校 Round7
Solved:5
Rank:296
E Find the median (线段树)
题意:最开始一个空的数组 4e5次操作 每次把Li,Ri中的每个数插入进来 问当前的中位数
题解:把这n个区间离散化去重以后 剩下m个点 可以分成m-1个连续的区间
有个巧妙的方法是把所有的右端点+1后 每两个点之间表示一个左闭右开的区间
然后线段树每个叶子节点就表示这个区间的信息 每次操作就是先区间更新再查询了
用la表示这个区间被覆盖了多少次 查询的时候类似整体二分 其实还可以维护一个叶子节点表示的区间长度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 4e5 + 5; int n, cnt;
int a1, b1, c1, m1;
int a2, b2, c2, m2;
int x[MAXN], y[MAXN];
int p[MAXN << 1], L[MAXN], R[MAXN];
ll pre[MAXN << 1]; ll sum[MAXN << 5];
int la[MAXN << 5];
int lz[MAXN << 5];
void pushup(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
} void pushdown(int l, int r, int rt) {
if(lz[rt]) {
lz[rt << 1] += lz[rt];
lz[rt << 1 | 1] += lz[rt];
la[rt << 1] += lz[rt];
la[rt << 1 | 1] += lz[rt];
int mid = l + r >> 1;
sum[rt << 1] += 1LL * lz[rt] * (pre[mid] - pre[l - 1]);
sum[rt << 1 | 1] += 1LL * lz[rt] * (pre[r] - pre[mid]);
lz[rt] = 0;
}
} void update(int ql, int qr, int l, int r, int rt) {
if(ql <= l && qr >= r) {
lz[rt]++; la[rt]++;
sum[rt] += pre[r] - pre[l - 1];
return;
}
pushdown(l, r, rt); int mid = l + r >> 1;
if(ql <= mid) update(ql, qr, l, mid, rt << 1);
if(qr > mid) update(ql, qr, mid + 1, r, rt << 1 | 1);
pushup(rt);
} int query(int l, int r, int rt, ll k) {
if(l == r) return p[l] + (k - 1) / la[rt];
pushdown(l, r, rt); int mid = l + r >> 1;
if(sum[rt << 1] >= k) return query(l, mid, rt << 1, k);
else return query(mid + 1, r, rt << 1 | 1, k - sum[rt << 1]);
} int main() {
cnt = 0;
scanf("%d", &n);
scanf("%d%d%d%d%d%d", &x[1], &x[2], &a1, &b1, &c1, &m1);
scanf("%d%d%d%d%d%d", &y[1], &y[2], &a2, &b2, &c2, &m2);
for(int i = 3; i <= n; i++) {
x[i] = (1LL * a1 * x[i - 1] + 1LL * b1 * x[i - 2] + 1LL * c1) % m1;
y[i] = (1LL * a2 * y[i - 1] + 1LL * b2 * y[i - 2] + 1LL * c2) % m2;
}
for(int i = 1; i <= n; i++) {
L[i] = min(x[i], y[i]) + 1;
R[i] = max(x[i], y[i]) + 2;
p[++cnt] = L[i], p[++cnt] = R[i];
}
sort(p + 1, p + 1 + cnt);
cnt = unique(p + 1, p + 1 + cnt) - p - 1;
p[cnt + 1] = p[cnt]; for(int i = 1; i <= cnt; i++) pre[i] = pre[i - 1] + 1LL * (p[i + 1] - p[i]); ll tot = 0;
for(int i = 1; i <= n; i++) {
int t1 = lower_bound(p + 1, p + 1 + cnt, L[i]) - p;
int t2 = lower_bound(p + 1, p + 1 + cnt, R[i]) - p - 1;
update(t1, t2, 1, cnt, 1);
tot += 1LL * (R[i] - L[i]); //左闭右开
printf("%d\n", query(1, cnt, 1, (tot + 1LL) / 2LL));
}
return 0;
}
E Find the median
F Energy Stones
题意:n个石头 初始能量Ei 每秒能量增长Li 最多能量Ci
有m次收割操作 每次选择一个时间点 将区间L,R内的石头能量都吸收 求最后一共吸收了多少能量
题解:因为他是问的最后一共吸收了多少能量 不是问的每一次
所以我们可以考虑每一个石头对答案产生了多少贡献
对于每一个石头 这m次收割只有部分收割到了它 假设收割了k次
如果我们知道了这k个时间点 除去第一个特判以外 每两个时间点之间会产出一次贡献
贡献要么是Ci 要么是Li*区间长度
对于n个石头 被收割的时间点有许多重复的 所以我们用set维护收割的时间点
在枚举到到第L个石头的时候把时间点插入进set 在枚举到底R + 1个石头的时候 删除这个时间点
然后一个树状数组维护长度为i的区间个数 一个树状数组维护长度为i的区间 长度和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5; int n, m;
int E[MAXN], L[MAXN], C[MAXN];
ll a[MAXN << 1], b[MAXN << 1];
vector<int> g[MAXN];
set<int> st; ll query1(int x) {
ll res = 0;
for(int i = x; i; i -= (i & -i)) res += a[i];
return res;
} ll query2(int x) {
ll res = 0;
for(int i = x; i; i -= (i & -i)) res += b[i];
return res;
} void add(int x, int val) {
for(int i = x; i <= 200001; i += (i & -i)) {
if(val > 0) a[i]++;
else a[i]--;
b[i] += 1LL * val;
}
} void inser(int x) {
if(st.empty()) {
st.insert(x);
return;
} auto pos = st.lower_bound(x);
if(pos == st.begin()) {
int t = (*pos) - x;
add(t, 1LL * t);
} else if(pos == st.end()) {
int t = x - (*(prev(pos)));
add(t, 1LL * t);
} else {
int t1 = x - (*(prev(pos)));
int t2 = (*pos) - x;
add(t1, 1LL * t1); add(t2, 1LL * t2);
add(t1 + t2, 1LL * (-t1 - t2));
}
st.insert(x);
} void del(int x) {
auto pos = st.find(x);
if(st.size() == 1) {
st.erase(pos);
return;
}
if(pos == st.begin()) {
int t = (*(next(pos))) - x;
add(t, 1LL * -t);
} else if(pos == prev(st.end())) {
int t = x - (*(prev(pos)));
add(t, 1LL * -t);
} else {
int t1 = x - (*(prev(pos)));
int t2 = (*(next(pos))) - x;
add(t1, 1LL * -t1); add(t2, 1LL * -t2);
add(t1 + t2, 1LL * (t1 + t2));
}
st.erase(pos);
} int main() {
int T;
scanf("%d", &T);
int cas = 0;
while(T--) {
st.clear();
ll ans = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d%d%d", &E[i], &L[i], &C[i]);
for(int i = 1; i <= n + 1; i++) g[i].clear();
memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); scanf("%d", &m);
for(int i = 1; i <= m; i++) {
int t, l, r; scanf("%d%d%d", &t, &l, &r);
g[l].push_back(t);
g[r + 1].push_back(-t);
} for(int i = 1; i <= n; i++) {
for(int j = 0; j < g[i].size(); j++) {
if(g[i][j] > 0) inser(g[i][j]);
else del(-g[i][j]);
} if(st.empty()) continue;
ans += min(1LL * C[i], 1LL * E[i] + 1LL * (*st.begin()) * L[i]);
if(L[i] == 0) continue;
int len = C[i] / L[i];
ans += 1LL * query2(len) * L[i];
ans += 1LL * C[i] * (st.size() - query1(len) - 1);
}
printf("Case #%d: %lld\n", ++cas, ans);
}
return 0;
}
F Energy stones
H pair
题意:给三个数a,b,c 求有多少对数满足 x & y > c || x ^ y < c x的范围在1-a y的范围在1-b;
题解:第一次写这种两个范围的数位DP.. 需要存的状态有
当前枚举到pos位 And=0表示x&y和c的大小不确定 1表示x&y已经大于c 2表示已经小于
Xor同理 然后存一下当前枚举两个数卡到的边界
因为数位dp是从0开始统计的 还多统计了0^y(y<c) 和x^0(x<c) 的答案 所以还要减去
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a, b, c;
ll dp[35][3][3][2][2]; ll dfs(int pos, int And, int Xor, int sj1, int sj2) {
if(pos == -1) {
if(And == 1 || Xor == 1) return 1;
else return 0;
}
if(dp[pos][And][Xor][sj1][sj2] != -1) return dp[pos][And][Xor][sj1][sj2]; ll res = 0;
int up1 = sj1 ? (a >> pos & 1) : 1;
int up2 = sj2 ? (b >> pos & 1) : 1; for(int i = 0; i <= up1; i++)
for(int j = 0; j <= up2; j++) {
int tand = And;
int txor = Xor;
if(tand == 0) {
if((i & j) > (c >> pos & 1)) tand = 1;
else if((i & j) < (c >> pos & 1)) tand = 2;
}
if(txor == 0) {
if((i ^ j) < (c >> pos & 1)) txor = 1;
else if((i ^ j) > (c >> pos & 1)) txor = 2;
}
res += dfs(pos - 1, tand, txor, sj1 && (i == up1), sj2 && (j == up2));
}
dp[pos][And][Xor][sj1][sj2] = res;
return res;
} int main() {
memset(dp, -1, sizeof(dp)); int T;
scanf("%d", &T);
while(T--) {
memset(dp, -1, sizeof(dp));
scanf("%d%d%d", &a, &b, &c);
printf("%lld\n", dfs(31, 0, 0, 1, 1) - min(a, c - 1) - min(b, c - 1) - 1);
}
return 0;
}
H pair
I Chessbord
题意:给出n,m 问构造一个k*k的矩阵 矩阵每个元素不小于m
且从每一行选一个数 且这k个数的属于不同的列 方案数
题解:枚举矩阵大小k 再枚举选出的k个元素的和j 为了计算方便 这个j等于实际的和减去k*m 那么元素大小可为0
我们发现合法的方案一定长这个样子 假定k为3
a1+b1 a2+b1 a3+b1
a1+b2 a2+b2 a3+b2
a1+b3 a2+b3 a3+b3
这样我们随便选出的和一定都等于a1+a2+a3+b1+b2+b3 这就是我们枚举的和j
这个方案数就等于C(j+2*k-1,2*k-1) 因为元素可以为0 那么我们让这2k项每个都先+1 分配完了再-1
等价于从j+2*k-1个空位中插2*k-1个板子 当然这样计算是有重复的
重复是因为假如让a1,a2,a3都加1 b1,b2,b3都减1 只要b都非负 这个方案是一样的 但是也计数了
所以我们就要减去b1,b2,b3都大于0的情况了 那么就等于让k项都+1 分配完了再-1
综上所述 一次枚举的方案数=C(j+2*k-1,2*k-1) - C(j+k-1,2*k-1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll jc[5005], ny[5005];
ll n, m; ll pow_mod(ll x, ll y) {
ll res = 1;
while(y) {
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
} ll C(ll x, ll y) {
if(x < 0 || y < 0 || x < y) return 0;
return jc[x] * ny[y] % mod * ny[x - y] % mod;
} int main() {
jc[0] = 1LL;
for(ll i = 1; i <= 5000; i++) jc[i] = jc[i - 1] * i % mod;
ny[5000] = pow_mod(jc[5000], mod - 2);
for(ll i = 4999; i >= 0; i--) ny[i] = ny[i + 1] * (i + 1) % mod; int T;
scanf("%d", &T);
while(T--) {
scanf("%lld%lld", &n, &m);
ll ans = 0;
for(ll i = 1; i <= n; i++) {
if(i * m > n) break;
for(ll j = 0; j <= n; j++) {
if(i * m + j > n) break;
ans += C(j + 2 * i - 1, 2 * i - 1) - C(j + i - 1, 2 * i - 1);
ans %= mod;
}
}
printf("%lld\n", (ans + mod) % mod);
}
return 0;
}
I Chessbord
2019牛客多校 Round7的更多相关文章
- 2019牛客多校第一场 I Points Division(动态规划+线段树)
2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...
- 2019牛客多校第二场 A Eddy Walker(概率推公式)
2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...
- 2019牛客多校第八场 F题 Flowers 计算几何+线段树
2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...
- 2019牛客多校 Round4
Solved:3 Rank:331 B xor 题意:5e4个集合 每个集合最多32个数 5e4个询问 询问l到r个集合是不是都有一个子集的xor和等于x 题解:在牛客多校第一场学了线性基 然后这个题 ...
- 2019牛客多校第一场E ABBA(DP)题解
链接:https://ac.nowcoder.com/acm/contest/881/E 来源:牛客网 ABBA 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语 ...
- 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数
目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...
- 2019牛客多校第四场 A meeting
链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...
- [2019牛客多校第二场][G. Polygons]
题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...
- 2019 牛客多校第一场 D Parity of Tuples
题目链接:https://ac.nowcoder.com/acm/contest/881/D 看此博客之前请先参阅吕凯飞的论文<集合幂级数的性质与应用及其快速算法>,论文中很多符号会被本文 ...
随机推荐
- Docker学习笔记之搭建Docker私有仓库
Docker仓库服务器名为Docker注册(registry)服务器.可以使用docker push命令将镜像上传到注册服务器,也可以使用docker pull命令下载服务器的镜像. Docker注册 ...
- postgresql中权限介绍
postgresql权限分为实例的权限,数据库的权限,模式的权限,对象的权限,表空间的权限 实例的权限:由pg_hba.conf文件控制,控制那些用户那些IP以哪种方式连接数据库 数据库的权限:是否允 ...
- 理解C#中的 async await
前言 一个老掉牙的话题,园子里的相关优秀文章已经有很多了,我写这篇文章完全是想以自己的思维方式来谈一谈自己的理解.(PS:文中涉及到了大量反编译源码,需要静下心来细细品味) 从简单开始 为了更容易理解 ...
- window安装nvm
先说一下背景,最近做的两个项目一个是祖传angularjs1.X版本另一个是react hooks结合tailwindcss,前者angularjs的node版本比较低,而tailwindcss的no ...
- openshift 3.11安装部署
openshift 3.11 安装部署 openshift安装部署 1 环境准备(所有节点) openshift 版本 v3.11 1.1 机器环境 ip cpu mem hostname OSsys ...
- DSL是什么?Elasticsearch的Query DSL又是什么?
1.DSL简介 DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言.而与 DSL 相对的就是 GPL,这里的 GPL 并不是我们知道的开源许可证(备注:G ...
- vue3.0 composition API
一.Setup函数 1.创建时间:组件创建之前被调用,优先与created被调用,this指向的实例为window,created所指向的实例为proxy 2.this指向:不会指向组件实例 3.参数 ...
- C#高级编程第11版 - 第五章 索引
[1]5.1 泛型概述 1.通过泛型,你可以创建独立于特定类型(contained types)以外的方法和类,而不用为不同类型编写多份同样功能的代码,你只需要创建一个方法或者类. 2.泛型类使用泛型 ...
- Java层面上下文切换
前言 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的"同一时间点",而是 多个任务 ...
- 自导自演的面试现场,趣学MySQL的10种文件
导读 Hi,大家好!我是白日梦!本文是MySQL专题的第 24 篇. 今天我要跟你分享的MySQL话题是:"自导自演的数据库面试现场--谈谈MySQL的10种文件" 换一种写作风格 ...