C - Attention

枚举,计算前缀和即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define MAXN 300005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0){putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
} int N,sum[2][MAXN];
char s[MAXN];
void Solve() {
read(N);
scanf("%s",s + 1);
for(int i = 1 ; i <= N ; ++i) {
sum[0][i] = sum[0][i - 1];sum[1][i] = sum[1][i - 1];
if(s[i] == 'E') sum[0][i]++;
else sum[1][i]++;
}
int ans = N;
for(int i = 1 ; i <= N ; ++i) {
ans = min(i - 1 - sum[0][i - 1] + (N - i - (sum[1][N] - sum[1][i])),ans);
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

D - Xor Sum 2

等价与一个区间每一数位只能有一个1

我们记录\(nxt[i][j]\)表示第\(i\)位数下一个第\(j\)位是1的位置是什么

我们枚举左端点,然后去计算右端点,取最小的右端点

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define pb push_back
#define MAXN 200005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0){putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
} int N,a[MAXN],nxt[MAXN][25];
void Solve() {
read(N);
for(int i = 1 ; i <= N ; ++i) read(a[i]);
for(int i = 0 ; i < 20 ; ++i) nxt[N + 1][i] = N + 1; for(int i = N ; i >= 1 ; --i) {
for(int j = 0 ; j < 20 ; ++j) {
if(a[i] >> j & 1) {
nxt[i][j] = i;
}
else nxt[i][j] = nxt[i + 1][j];
}
}
int64 ans = 0;
for(int i = 1 ; i <= N ; ++i) {
int r = N;
for(int j = 0 ; j < 20 ; ++j) {
int t = nxt[i][j];
if(t != N + 1) r = min(r,nxt[t + 1][j] - 1);
}
ans += (r - i + 1);
}
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}

E - Range Minimum Queries

二分一个差值,枚举最小值,我们会得到一个可取区间

对于枚举的最小值,我们把区间里所有大于等于它的都标成1,对于一段连续的1区间,统计一下区间里有多少个数在范围内,记为\(cnt\),设长度为L,这个区间可以满足的询问个数就是\(min(L - K + 1,cnt)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 2005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,K,Q;
int a[MAXN],val[MAXN],tot; bool check(int mid) {
for(int i = 1 ; i <= tot ; ++i) {
int l = val[i],r = val[i] + mid;
int res = 0,st = 0,ed = -1,cnt = 0;
for(int j = 1 ; j <= N ; ++j) {
if(a[j] >= l) {
if(!st) st = ed = j;
ed = max(ed,j);
if(a[j] <= r) ++cnt;
}
else {
if(ed - st + 1 >= K) {
res += min(cnt,(ed - st + 1) - K + 1);
}
st = 0,ed = -1;cnt = 0;
}
}
if(ed - st + 1 >= K) {
res += min(cnt,(ed - st + 1) - K + 1);
}
if(res >= Q) return true;
}
return false;
}
void Init() {
read(N);read(K);read(Q);
for(int i = 1 ; i <= N ; ++i) {
read(a[i]);
val[i] = a[i];
}
sort(val + 1,val + N + 1);
tot = unique(val + 1,val + N + 1) - val - 1; }
void Solve() {
int L = 0,R = val[tot] - val[1];
while(L < R) {
int mid = (L + R) >> 1;
if(check(mid)) R = mid;
else L = mid + 1;
}
out(L);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}

F - Donation

感觉这道题和之前见过的某道题有点一样,又不太一样……

智商--,看了好久题解才想明白一点。。。

就是……我们先想一下,我们如果按照每个点交钱的顺序写下一个序列

对于第k次选走的点,我们需要的是我们钱数\(w\),需要有\(w >= \sum_{i = 1}^{k}B_{id[i]} + max(A_{id[k]} - B_{id[k]},0)\)

最后我们需要的是序列最大值,我们要最大值最小

并且,要求这个序列付完钱的点,之后不会再经过了

我们对于每个点求一个\(C[i]\)为\(max(A[i] - B[i],0)\)

我们发现,如果一个在\(C[i]\)最大值被选择之前,答案的下限在不断提高

那么我们可能会考虑到,我们要拿走u点之后,我们的图可能会裂成很多子图,我们需要进入其中一个子图,然后将剩下子图的B连带u点累加起来加上\(C[u]\)来累加答案

那么,在最大值拿走之前,假设最大值拿走之后我们进入的子图是\(G_{i}\),那么,\(G_{i}\)里的任何一点\(w\)为什么不能先于u之前拿走呢?

这是我很难想明白的一件事,我现在也许能谈一下理解

当\(w\)点在\(u\)之前时,\(B[w]\)必定会被统计到答案的一个下限中,如果\(w\)在\(u\)点之后,\(B[w]\)可能不会累加进最后的答案用来更新,也可能会,而我们希望的是答案更优秀,\(w\)在\(u\)之前答案不可能变小,而\(w\)在\(u\)之后,答案可能会变小但是绝对不会变大,所以我们把其他子图访问完之后选择访问这个子图

我们发现,这刚刚好是一个子问题,我们对这个子图取出最大值作为根,然后重新求一下这个子图的答案就可以,我们可以用dp解决这个问题,对于每个子图都进入一遍求值

然而,好像又有了一个新的问题,我们怎么求每次去掉最大值后,每个子图里的最大值,暴力求显然是\(n^2\)的

我们发现,全局最大值和每个子图里的最大值连边,每个子图里的最大值和去掉最大值后新裂成的子图最大值连边,刚好可以在图中构建出一棵树

而C值最小的点,必然是叶子

我们按C从小到大遍历每个点,访问周边的所有点,如果周边的点有C值小于它的,就让周边的点所在的子图的最大值(用并查集维护)作为它的儿子就好了

写出来的代码非常清晰,又简单好写,思维含量又高,可以说是虐我这种蒟蒻的好题了。

代码

#include <bits/stdc++.h>
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define eps 1e-8
#define mo 974711
#define MAXN 200005
#define pii pair<int,int>
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
struct node {
int to,next;
}E[MAXN * 2];
int head[MAXN],sumE,id[MAXN],ra[MAXN],f[MAXN];
int64 A[MAXN],B[MAXN],C[MAXN],dp[MAXN],siz[MAXN];
vector<int> son[MAXN];
int getfa(int x) {
return f[x] == x ? x : f[x] = getfa(f[x]);
}
bool cmp(int s,int t) {
return C[s] < C[t];
}
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) {
read(A[i]);read(B[i]);C[i] = max(A[i] - B[i],0LL);
id[i] = i;
}
sort(id + 1,id + N + 1,cmp);
for(int i = 1 ; i <= N ; ++i) ra[id[i]] = i;
int u,v;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);
add(u,v);add(v,u);
}
}
void dfs1(int u) {
siz[u] += B[u];
for(auto v : son[u]) {
dfs1(v);
siz[u] += siz[v];
}
}
void dfs2(int u) {
if(son[u].size() == 0) {
dp[u] = B[u] + C[u];
return;
}
dp[u] = 1e18;
for(auto v : son[u]) {
dfs2(v);
dp[u] = min(siz[u] - siz[v] + max(C[u],dp[v]),dp[u]);
}
}
void Solve() {
for(int i = 1 ; i <= N ; ++i) f[i] = i;
for(int i = 1 ; i <= N ; ++i) {
int u = id[i];
for(int j = head[u] ; j ; j = E[j].next) {
int v = E[j].to;
if(ra[getfa(v)] < ra[u] && getfa(v) != u) {
son[u].pb(getfa(v));
f[getfa(v)] = u;
}
}
}
dfs1(id[N]);
dfs2(id[N]);
out(dp[id[N]]);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

【AtCoder】ARC098题解的更多相关文章

  1. AtCoder ExaWizards2019题解

    AtCoder ExaWizards2019题解 AtCoder (因为代码直接用模板写的,可能有点冗长) A.Regular Triangle 给你三根棍子的长度,问你能否用他们组成等边三角形. 什 ...

  2. 【赛时总结】 ◇赛时·I◇ AtCoder ARC-098

    ◆赛时I◆ ARC-098 ■试题&解析■ ◆本场最水◆ C-Attention 长点儿信心吧-- [AtCoder ARC-098 C] [解析] 既然只存在左右(东西)两个朝向,那么领导右 ...

  3. KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解

    KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解 哦淦我已经菜到被ABC吊打了. A - Century 首先把当前年 ...

  4. AT2370 Piling Up

    https://www.luogu.org/jump/atcoder/2370 题解 答案不是\(2^{2m}\)因为每轮的第一次取球可能会不够. 我们可以设\(dp[i][j]\)表示到了第\(i\ ...

  5. Triple Shift

    来源:Atcoder ARC 136 B - Triple Shift (atcoder.jp) 题解:这道题我们不可能去硬模拟(大多数这种题都不能这样去模拟的),然后我们就要去发现特性, 发现把 a ...

  6. 重修 Slope Trick(看这篇绝对够!)

    Slope Trick 算法存在十余载了,但是我没有找到多少拍手叫好的讲解 blog,所以凭借本人粗拙的理解来写这篇文章. 本文除标明外所有图片均为本人手绘(若丑见谅),画图真的不容易啊 qwq(无耻 ...

  7. AtCoder Regular Contest 094 (ARC094) CDE题解

    原文链接http://www.cnblogs.com/zhouzhendong/p/8735114.html $AtCoder\ Regular\ Contest\ 094(ARC094)\ CDE$ ...

  8. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  9. AtCoder Grand Contest 017 题解

    A - Biscuits 题目: 给出 \(n\) 个物品,每个物品有一个权值. 问有多少种选取方式使得物品权值之和 \(\bmod\space 2\) 为 \(p\). \(n \leq 50\) ...

随机推荐

  1. in packet sniffer

    in packet sniffer 来源 https://kb.fortinet.com/kb/microsites/search.do?cmd=displayKC&docType=kc&am ...

  2. 【刷题】LOJ 6008 「网络流 24 题」餐巾计划

    题目描述 一个餐厅在相继的 \(n\) 天里,每天需用的餐巾数不尽相同.假设第 \(i\) 天需要 \(r_i\) 块餐巾.餐厅可以购买新的餐巾,每块餐巾的费用为 \(P\) 分:或者把旧餐巾送到快洗 ...

  3. 【Revit API】改变填充区域的填充样式

    话不多说,直接上代码 var target = pattern.Target; var name = pattern.Name; var fpElem = FillPatternElement.Get ...

  4. 【bzoj4066】 简单题

    http://www.lydsy.com/JudgeOnline/problem.php?id=4066 (题目链接) 题意 维护一个矩阵,两个操作,给某一个元素加上A,求其中一个子矩阵的元素之和.强 ...

  5. 【CH4201】楼兰图腾

    题目大意:给定一个长度为 N 的序列,从序列中任意挑出三个数,求满足中间的数字值最小(最大)有多少种情况. 题解:建立在值域上的树状数组,从左到右扫描一遍序列,统计出每个点左边有多少个数大于(小于)该 ...

  6. nginx 重写URL尾部斜杠

    1. 在URL结尾添加斜杠 在虚拟主机中这么添加一条改写规则: rewrite ^(.*[^/])$ $1/ permanent;或者rewrite ^([/\w-_]*[^/])$ $1/ perm ...

  7. SpringBoot 读取配置文件及profiles切换配置文件

    读取核心配置文件 核心配置文件是指在resources根目录下的application.properties或application.yml配置文件,读取这两个配置文件的方法有两种,都比较简单. 先创 ...

  8. 对 JavaScript 下 namespace 功能的简单分析

    前些天在剥离 百度随心听 的播放器引擎时,看到了一个namespace方法,觉得新奇,当然只是对于我自己而言,我入门js不久,经验尚浅.之前看到网易还是新浪还是什么什么网站来着,也是用类似这种东西的, ...

  9. 使用渐进式JPEG来提升用户体验

    今天才认识到原来JPEG文件有两种保存方式他们分别是Baseline JPEG(标准型)和Progressive JPEG(渐进式).两种格式有相同尺寸以及图像数据,他们的扩展名也是相同的,唯一的区别 ...

  10. 【CodeForces】983 E. NN country 树上倍增+二维数点

    [题目]E. NN country [题意]给定n个点的树和m条链,q次询问一条链(a,b)最少被多少条给定的链覆盖.\(n,m,q \leq 2*10^5\). [算法]树上倍增+二维数点(树状数组 ...