CF 1037B  Reach Median

班上 n个同学(n 是奇数)排成一排站队,为了美观,需要大家高度的中位数是 x。

你可以让同学们在脚下垫木板或者稍微蹲一点来达成这个目标。对任意一位同学的身高减少或者增加1的代价都是1。问

你最少花费多少代价可以让最后大家高度的中位数是x。

solution:
基于一个贪心,现将序列排序。设当前的中位数为MID,位置是pos

那么如果MID比x大,那么将MID=x计算代价,我们的中位数要左移然后就考虑将pos左侧所有小于x的数全部赋值为x计算代价

如果MID比x小,那么将MID=x计算代价,我们中位数要右移就考虑将pos右侧所有大于x的数全部赋值为x计算代价

然后输出答案即可。

Code:

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int MAXN=2e5+;
int a[MAXN],n,x;
inline int read()
{
int X=,w=; char c=;
while (!(c>=''&&c<='')) w|=c=='-',c=getchar();
while (c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
inline void write(int x)
{
if (x<) { x=-x;putchar('-');}
if (x>) write(x/);
putchar(''+x%);
}
inline void writeln(int x){write(x);putchar('\n');} signed main()
{
n=read(); x=read();
for (int i=;i<=n;i++) a[i]=read();
sort(a+,a++n);
int pos=(n+)/,ans=;
if (x<a[pos]) {
for (int i=;i<=pos;i++)
if (a[i]>x) ans+=a[i]-x;
} else {
for (int i=pos;i<=n;i++)
if (a[i]<x) ans+=x-a[i];
}
writeln(ans);
return ;
}

CF 1037E  Reach Median

题目描述

There are nn persons who initially don't know each other. On each morning, two of them, who were not friends before, become friends.

We want to plan a trip for every evening of mm days. On each trip, you have to select a group of people that will go on the trip. For every person, one of the following should hold:

  • Either this person does not go on the trip,
  • Or at least kk of his friends also go on the trip.

Note that the friendship is not transitive. That is, if aa and bb are friends and bb and cc are friends, it does not necessarily imply that aa and cc are friends.

For each day, find the maximum number of people that can go on the trip on that day.

输入输出格式

输入格式:

The first line contains three integers nn , mm , and kk ( 2 \leq n \leq 2 \cdot 10^5, 1 \leq m \leq 2 \cdot 10^52≤n≤2⋅105,1≤m≤2⋅105 , 1 \le k < n1≤k<n ) — the number of people, the number of days and the number of friends each person on the trip should have in the group.

The ii -th ( 1 \leq i \leq m1≤i≤m ) of the next mm lines contains two integers xx and yy ( 1\leq x, y\leq n1≤x,y≤n , x\ne yx≠y ), meaning that persons xx and yy become friends on the morning of day ii . It is guaranteed that xx and yy were not friends before.

输出格式:

Print exactly mm lines, where the ii -th of them ( 1\leq i\leq m1≤i≤m ) contains the maximum number of people that can go on the trip on the evening of the day ii .

输入输出样例

输入样例#1: 复制

4 4 2
2 3
1 2
1 3
1 4
输出样例#1: 复制

0
0
3
3
输入样例#2: 复制

5 8 2
2 1
4 2
5 4
5 2
4 3
5 1
4 1
3 2
输出样例#2: 复制

0
0
0
3
3
4
4
5
输入样例#3: 复制

5 7 2
1 5
3 2
2 5
3 4
1 2
5 3
1 3
输出样例#3: 复制

0
0
0
0
3
4
4

说明

In the first example,

  • 1,2,31,2,3 can go on day 33 and 44 .

In the second example,

  • 2,4,52,4,5 can go on day 44 and 55 .
  • 1,2,4,51,2,4,5 can go on day 66 and 77 .
  • 1,2,3,4,51,2,3,4,5 can go on day 88 .

In the third example,

  • 1,2,51,2,5 can go on day 55 .
  • 1,2,3,51,2,3,5 can go on day 66 and 77 .

一共有n个人,他们开始互不认识,而每天早上不认识的两个人会变成朋友。一共有m天,每天晚上有的人要去旅行,去旅行的人必须满足ta有至少k个朋友也去旅行

求每天去旅行的最大人数

输入格式:

第一行3个整数,表示n,m,kn,m,k

往下m行,每行两个整数x,yx,y,表示这天早上xx和yy会变成朋友

输出格式:

共mm行,每行一个整数,表示每天晚上最多能去旅游的人数

solution:

考虑离线做首先维护一个du,即图上节点的入度如果入度小于k那么就删除这个节点然后维护删去这个点以后发生的事情(比如其他边被删去,其他点又被删去)

这样维护就是一边bfs就行(dfs也行)

具体来说就是先建好图吧最终的状态O(n)统计一遍然后,依次删边,删边的时候注意将du[u]--,du[v]--,如果du[u]或者du[v]等于0那么把这个点删去然后维护全局的答案

然后由于这个点删去了,那么和这个点有关系的所有边都得删去了,然后又造成一部分点的 du 减少于是又得维护这些点的状态删去或者不删。。这就要bfs了。。。

注意删过的点和边不用重复删,就是弄两个数组看看对应的点和边还在不在就行了。

Code:

# include <bits/stdc++.h>
# define int long long
using namespace std;
const int MAXN=2e5+;
struct Edge{ int u,v;};
struct A{ int node,id;};
vector<A>E[MAXN];
vector<Edge>R;
int ret,n,m,k,du[MAXN];
bool ok[MAXN],able[MAXN];
inline int read()
{
int X=,w=; char c=;
while (!(c>=''&&c<='')) w|=c=='-',c=getchar();
while (c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void del(int u)
{
if (ok[u]==false) return;
ret--; ok[u]=false; du[u]=;
queue<int>q; q.push(u);
while (!q.empty()) {
int u=q.front();q.pop();
for (int i=;i<E[u].size();i++) {
int v=E[u][i].node;
if (ok[v]==false||able[E[u][i].id]==false) continue;
du[v]--;
able[E[u][i].id]=false;
if (du[v]<k) ok[v]=false,ret--,q.push(v);
}
}
}
void erase(int id)
{
if (able[id]==false) return;
int x=R[id].u,y=R[id].v;
able[id]=false;
du[x]--;if (du[x]<k&&ok[x]) del(x);
du[y]--;if (du[y]<k&&ok[y]) del(y);
}
signed main()
{
n=read();m=read();k=read();
for (int i=;i<=m;i++) {
int u=read(),v=read();
E[u].push_back((A){v,i-});
E[v].push_back((A){u,i-});
du[u]++; du[v]++;
R.push_back((Edge){u,v});
}
ret=n;
memset(ok,true,sizeof(ok));
memset(able,true,sizeof(able));
for (int i=;i<=n;i++) if (du[i]<k) del(i);
stack<int>Ans;
for (int w=R.size()-;w>=;w--) {
Ans.push(ret);
erase(w);
}
while (!Ans.empty()) printf("%lld\n",Ans.top()),Ans.pop();
return ;
}

运气大战

你的班上nn个同学要去参加一项集体比赛。每个人有实力值和运气值。每个人的实力值是确定的,但是运气值是飘忽不定的。一个人的发挥是他的实力值wiwi 和运气值的乘积,即wi⋅rciwi⋅rci。班级的发挥是所有人发挥之和。每个人有一个初始运气值riri,但是每次比赛的时候,每个人的运气值是所有人运气值的一个排列,并且要满足,排列之后ii的运气值不是riri。即满足,ii的运气值是rcirci,{ci}{ci}是1−n1−n的排列,且满足ci≠ici≠i。

现在有QQ场比赛,每场比赛前会交换两人的初始运气值。问你每场比赛班级可以获得的最大发挥是多少。

输入格式

第一行两个整数 nn 和 QQ。

第二行nn个整数w1,...,wnw1,...,wn。

第三行nn个整数r1,...,rnr1,...,rn。

接下来QQ行,每行两个整数ai,biai,bi表示每次要交换运气值的两个人的编号。

输出格式

共QQ行,每行一个答案,表示这场比赛班级的最大发挥。

样例1

输入

5 5
25 1 16 26 19
11 27 4 8 20
1 5
1 5
2 5
1 2
5 4

输出

1527
1543
1543
1536
1536

样例2

输入


输出


数据范围

20% n≤10,q≤10n≤10,q≤10

另30% n≤1000,q≤100n≤1000,q≤100

另20% n≤30000,q≤500n≤30000,q≤500

100% 2≤n≤30000,1≤q≤10000,1≤wi,ri≤1e6,1≤ai≠bi≤n

本题时限:5s

由于排序不等式,我们尽量想顺序放。两边都排序。

由于 n 个不能配的干扰,又不能完全顺序放。

有个结论,最后匹配出第 i 个人的运气值是第 j 个的话,|i-j|\le2∣i−j∣≤2。这个结论从最小化逆序对的个数来看,自己把附近几个线连起来画一画证明一下。

这样就可以用 dp[i]表示到 i 为止所有配好的最优答案。计算的时候需要用到前三轮的答案然后讨论一下。这个是 O(nq)的,可以过70%。

用线段树记录区间答案。区间记录这样的信息:把这个区间前0-2个和后0-2个元素去掉的答案,用3x3的矩阵维护。这样复杂度是O(qlogn)。

#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std; #define A first
#define B second
typedef long long ll; int n,q;
vector<pair<int,int> > L, R;
int whereL[], whereR[];
ll cost[][];
ll dp[]; const ll INF = -3.1e16; inline ll match(int a, int b) {
if (a<= || b<= || a>n || b>n) return INF;
return (ll) L[a].A*R[b].A;
} inline void update(int i) {
if (i<= || i>n) return;
cost[i][] = match(i,i+)+match(i+,i);
cost[i][] = max(match(i,i+)+match(i+,i+)+match(i+,i),match(i,i+)+match(i+,i)+match(i+,i+));
} int main() {
scanf("%d%d",&n,&q);
for (int i=;i<=n;i++) {
L.push_back(make_pair(,i));
R.push_back(make_pair(,i));
}
for (int i=;i<=n;i++) scanf("%d",&L[i].A);
for (int i=;i<=n;i++) scanf("%d",&R[i].A);
sort(L.begin(),L.end());
sort(R.begin(),R.end());
for (int i=;i<=n;i++) {
whereL[L[i].B] = i;
whereR[R[i].B] = i;
}
for (int i=;i<=n;i++) update(i);
for (int Q=;Q<q;Q++) {
int a,b;
scanf("%d%d",&a,&b);
swap(R[whereR[a]].B,R[whereR[b]].B);
swap(whereR[a],whereR[b]);
for (int i=-;i<=;i++) {
update(whereL[a]+i);
update(whereR[a]+i);
update(whereL[b]+i);
update(whereR[b]+i);
}
dp[n+] = ;
for (int i=n;i;i--) {
dp[i] = max(dp[i+]+cost[i][],dp[i+]+cost[i][]);
if (L[i].B!=R[i].B) dp[i] = max(dp[i],(ll) L[i].A*R[i].A+dp[i+]);
}
printf("%lld\n",dp[]);
} return ;
}

NOI.AC 20181103 题解的更多相关文章

  1. NOI.AC 31 MST——整数划分相关的图论(生成树、哈希)

    题目:http://noi.ac/problem/31 模拟 kruscal 的建最小生成树的过程,我们应该把树边一条一条加进去:在加下一条之前先把权值在这一条到下一条的之间的那些边都连上.连的时候要 ...

  2. [NOI.AC 2018NOIP模拟赛 第三场 ] 染色 解题报告 (DP)

    题目链接:http://noi.ac/contest/12/problem/37 题目: 小W收到了一张纸带,纸带上有 n个位置.现在他想把这个纸带染色,他一共有 m 种颜色,每个位置都可以染任意颜色 ...

  3. # NOI.AC省选赛 第五场T1 子集,与&最大值

    NOI.AC省选赛 第五场T1 A. Mas的童年 题目链接 http://noi.ac/problem/309 思路 0x00 \(n^2\)的暴力挺简单的. ans=max(ans,xor[j-1 ...

  4. NOI.ac #31 MST DP、哈希

    题目传送门:http://noi.ac/problem/31 一道思路好题考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个 ...

  5. NOI.AC NOIP模拟赛 第五场 游记

    NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...

  6. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  7. NOI.AC NOIP模拟赛 第二场 补记

    NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...

  8. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  9. NOI.AC NOIP模拟赛 第四场 补记

    NOI.AC NOIP模拟赛 第四场 补记 子图 题目大意: 一张\(n(n\le5\times10^5)\)个点,\(m(m\le5\times10^5)\)条边的无向图.删去第\(i\)条边需要\ ...

随机推荐

  1. 避免写慢SQL

    最近在整理数据库中的慢SQL,同时也查询了相关资料.记录一下,要学会使用执行计划来分析SQL. 1. 为查询缓存优化你的查询 大多数的MySQL服务器都开启了查询缓存.这是提高性最有效的方法之一,而且 ...

  2. ASP.NET Core 3.0 实战:构建多版本 API 接口

    第一次在博客写分享,请多多捧场,如有歧义请多多包含! 因为业务需求发展需要,所以API接口的变更升级是必不可少的事情,而原有的接口是不可能马上停止使用的.例如:Login接口为例,1.0版本之返回用户 ...

  3. Python3入门(三)——Python基础语法

    一.基本语法 1.行和缩进 Python中,不使用括号来表示代码的类和函数定义块或流程控制. 代码块是由行缩进,缩进位的数目是可变的,但是在块中的所有语句必须缩进相同的量. 如下所示: a = 100 ...

  4. libgdx学习记录12——圆角矩形CircleRect

    libgdx提供了ShapeRenderer这个工具,用它可以画点.画线.画圆.画矩形.画椭圆.画扇形,但是没有提供画圆角矩形的方法. 刚开始自己尝试分成8端,4端画直线,4端画扇形,发现多了半径几部 ...

  5. PAT甲题题解-1028. List Sorting (25)-水排序

    #include <iostream> #include <cstdio> #include <algorithm> #include <string.h&g ...

  6. 第一Sprint阶段对各组提出的意见

    组号  组名 意见 1 理财猫 1.界面深色的部分,字体应调成亮色,可以适当美化字体. 2.希望能够自动记录花销,而不是只能手动“记一笔”. 3.功能略少,比如可以添加“收入详情”.“支出详情”. 2 ...

  7. 软件项目第一次sprint评分表

  8. Book Review 《构建之法》-2

    -敏捷流程包括了几大原则:Backlog.burn-down.Sprint.Scrum. 敏捷开发注重个人之间的交流,提倡尽早的交付有价值的软件满足顾客的需求, 在开发过程中不断与客户进行交互,变化. ...

  9. C与C++的编程风格区别

    c和c++都是在实践中发展起来的语言.实用性极强.c是与UNIX/Linux的发展相辅相成的.而C++是B.S为了摆脱c与硬件以及底层过于紧密的苦恼,而开发的语言.C++可以说就是c语言的超集.任何c ...

  10. VS2013的安装与测试

    第一步:下载完成之后点击安装,在安装过程中会出现很多选择,选择社区版(c++),安装完成: 第二步:安装完成之后打开VS2013,如图所示:   第三步:按以下步骤进行 第四步:点击[OK]之后 第五 ...