首页 > 其他分享 >【题解】Educational Codeforces Round 146(CF1814)

【题解】Educational Codeforces Round 146(CF1814)

时间:2023-08-13 19:33:48浏览次数:46  
标签:146 10 Educational le 题目 int 题解 times leq

而且怎么感觉 E,F 比 D 要简单很多,大概是因为比较套路吧[惊恐]

A.Coins

题目描述:

本题一共有 \(t\) 组数据。

每组数据包含两个整数 \(n\) 和 \(k\),如果存在两个非负整数 \(x,y\),满足 \(2\times x+k\times y=n\),输出 YES,否则输出 NOyes,Yes,NO,nO 均可)。

题目分析:

注意到 \(y\) 可能的取值只有 \(0,1\),因为如果 \(y \ge 2\) 那么必然有 \(y = (2p + y')\),所以可以直接用 \(2x\) 表示出前面的贡献。

B.Long Legs

题目描述:

给你一个无限大小的棋盘,一个机器人初始位置为 \((0,0)\),初始每次可移动的长度为 \(1\)。

对于一个当前在 \((x,y)\) 的机器人,且它当前的可移动长度为 \(m\)(初始为 \(1\))。则它可以耗费 \(1\) 个时间进行如下操作之一:

  1. 移动到 \((x+m,y)\)
  2. 移动到 \((x,y+m)\)
  3. 使得 \(m=m+1\)

注意:在当前位置使得 \(m=m+1\) 后会影响后面的操作。

现在给你两个正整数 \(a,b(1 \leq a,b \leq 10^9)\),问机器人最少需要多少单位时间可以到达 \((a,b)\)。

题目分析:

最优的方案肯定先用操作 \(3\) 将 \(m\) 变成某个数然后一直用操作 \(1\) 和操作 \(2\)。

因为考虑如果我们在改变 \(m\) 的过程中使用了操作 \(1\) 和操作 \(2\) 显然不如留到最后用产生的贡献多,而他们需要的时间是一样的。

当然如果 \(m\) 最后大于我们要到达的位置肯定就是在中间用 \(1\) 次操作过去然后就不管了,但是这其实没什么影响。

所以可以直接枚举 \(m\) 变成多少,然后答案就是 \(\lceil \frac{a}{m} \rceil + \lceil \frac{b}{m} \rceil\),因为 \(m\) 特别大的时候答案一定不优,所以大概枚举到 \(10^5 \sim 10^6\) 就差不多了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9+5;
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		int x,y;scanf("%d%d",&x,&y);
		int ans = INF;
		for(int i=1; i<=1000000; i++){
			ans = min(ans,(x + i - 1) / i + (y + i - 1) / i + (i-1));
		}
		printf("%d\n",ans);
	}
	return 0;
}

C.Search in Parallel

题目描述:

要求构造两个序列 \(a,b\) 使得两个序列的长度之和为 \(n\)。

对于查询 \(i\) 所需要的时间定义为:

有两个机器人,同时从 \(a,b\) 的第一个数开始取,每一次 \(a\) 拿出的数会花费 \(s_1\) 的时间扫描,\(b\) 拿出的数会花费 \(s_2\) 的时间扫描,两个机器人同时行动互相独立,不存在

等待另一个机器人一起拿下一个数的情况,当某一个机器人扫描完成之后发现这个数为 \(i\) 则从这个时刻停止机器人的所有操作,并且将这段时间定义为需要的时间。

我们会对 \(i\in [1,n]\) 查询 \(a_i\) 次,要求构造的序列满足查询的总时间最小。

题目分析:

一个显然的想法就是查询次数越多的越放到前面,这样就只需要判断将当前数插入哪个序列造成的贡献更小就放入哪个序列就可以了。
设序列中有 \(cnt\) 个数,则查询这个数的时间就是 \((cnt+1) \times s\)。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+5;
int cnt[N],p[N];
vector<int> v1,v2;
bool cmp(int a,int b){
	return cnt[a] > cnt[b];
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;scanf("%d",&T);
	while(T--){
		int n,s1,s2;scanf("%d%d%d",&n,&s1,&s2);
		for(int i=1; i<=n; i++){
			scanf("%d",&cnt[i]);
		}
		for(int i=1; i<=n; i++)	p[i] = i;
		sort(p+1,p+n+1,cmp);
		
		for(int i=1; i<=n; i++){
			if(s1 * (int)(v1.size() + 1) > s2 * ((int)v2.size() + 1))	
				v2.push_back(p[i]);
			else	v1.push_back(p[i]);
		}
		
		printf("%d ",(int)v1.size());
		for(auto x : v1)	printf("%d ",x);
		printf("\n");
		printf("%d ",(int)v2.size());
		for(auto x : v2)	printf("%d ",x);
		printf("\n");
		
		v1.clear(),v2.clear();
		for(int i=1; i<=n; i++)	cnt[i] = 0;
	}
	return 0;
}

D.Balancing Weapons

题目描述:

有 \(n\) 把枪,第 \(i\) 把枪的攻击力是 \(p_i = f_i \cdot d_i\)。你需要调整 \(d_i\) 使得 $ \max\limits_{1 \le i \le n}{p_i} - \min\limits_{1 \le i \le n}{p_i} \le k $,要保证 \(d_i > 0\),求最少调整几把枪的 \(d_i\) 可以满足条件。
\(n \le 3000,k \le 1500,1 \le f_i \le 2000,1 \le d_i \le 10^9\)

题目分析:

我们肯定是让最大值变小或者让最小值变大,也就是会保留排序后的一个区间,使得不在区间内部的数尽可能通过调整靠近这个区间。

所以其实每个数通过调整能得到的有用的数只有 \(O(n)\) 个,可以直接将这些数记下来然后双指针扫描区间(双指针是因为有极差不超过 \(k\) 的限制),如果当前区间使得所有的数都有某个调整得到的数出现过那么就更新答案。

E.Chain Chips

题目描述:

在一条长度为 \(n\) 的链上,有 \(1\sim n\) 这 \(n\) 个点,第 \(i\) 条边连接着第 \(i\) 个点到第 \(i+1\) 个点,长度是 \(w_i\) 。

在一开始,在第 \(i\) 个点上都停着一辆车 \(i\) 。现在,你需要通过这些道路,移动一些车辆,使得每一辆车都不停在它的初始位置上,同时每个位置最终也仅有一辆车,并且车的移动总距离尽可能小。

接下来会有 \(m\) 组询问,每组询问会修改一条边的边权,你需要输出修改后的车的移动的最小距离。修改不独立,车并不会真的移动。

\(n,m\leq 2\times 10^5\)

题目分析:

看上去比较想贪心,也就是看看每一个边造成的贡献,但是好像不大可能贪。

虽然不能贪心但是我们也可以由此联想到 \(dp\),考虑我们一条边肯定最多造成 \(2\) 次贡献,也就是让左右的车交换,因为交换多次其实没意义,我们只需要错位即可。

而因为错位是一个必须要管的东西,所以考虑记 \(f[i][0/1]\) 表示前 \(i\) 个位置第 \(i\) 个位置上是否为第 \(i\) 辆车,且 \([1,i-1]\) 已经错位的最小移动距离。

转移就是枚举第 \(i-1\) 个位置是什么状态然后判断是否交换 \(i\) 和 \(i-1\):

\[\begin{aligned} f[i][0] &= \min(f[i-1][0] + f[i-1][1]) + 2 \times w_i \\ f[i][1] &= f[i-1][0] \end{aligned} \]

发现这个东西就是一个 \(\min+\) 矩乘的形式,因为带修所以直接线段树维护矩阵乘法去优化 \(dp\) 就好了,或者叫做 \(ddp\)。

矩阵大概就是下面这个东西:

\[\begin{bmatrix} f_{i-1,0} & f_{i-1,1} \end{bmatrix} \times \begin{bmatrix} 2 \times w_i & 0 \\ 2 \times w_i & \infty \\ \end{bmatrix} = \begin{bmatrix} f_{i,0} & f_{i,1} \end{bmatrix} \]

自己根据矩阵乘法的定义就可以发现,这个就是将转移方程再写了一遍而已。
写的时候要注意 \(dp\) 的初值啊。(我就因为这里写错了寄了十几分钟)

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
const int INF = 1e9+5;
int n,w[N],dp[N][2];
int get_ans(){   //那个暴力 dp 
	dp[1][1] = 0,dp[1][0] = INF;
	for(int i=2; i<=n; i++){
		dp[i][0] = min(dp[i-1][0],dp[i-1][1]) + w[i-1];
		dp[i][1] = dp[i-1][0];
	}
	return dp[n][0] * 2;
}
struct matrix{
	int n,m;
	int a[3][3];
	matrix(){
		memset(a,0x3f,sizeof(a));
	}
}M[4 * N];
matrix operator * (matrix A,matrix B){
	matrix C;
	C.n = A.n,C.m = B.m;
	for(int i=1; i<=C.n; i++){
		for(int j=1; j<=C.m; j++){
			for(int k=1; k<=A.m; k++){
				C.a[i][j] = min(C.a[i][j],A.a[i][k] + B.a[k][j]);
			}
		}
	}
	return C;
}
void build(int now,int now_l,int now_r){
	if(now_l == now_r){
		M[now].a[1][1] = M[now].a[2][1] = w[now_l];
		M[now].a[1][2] = 0;
		M[now].a[2][2] = INF;
		M[now].n = M[now].m = 2;
		return;
	}
	int mid = (now_l + now_r) >> 1;
	build(now<<1,now_l,mid);build(now<<1|1,mid+1,now_r);
	M[now] = M[now<<1] * M[now<<1|1];
}
void modify(int now,int now_l,int now_r,int pos,int val){
	if(now_l == now_r){
		M[now].a[1][1] = M[now].a[2][1] = val;
		return;
	}
	int mid = (now_l + now_r)>>1;
	if(pos <= mid)	modify(now<<1,now_l,mid,pos,val);
	if(pos > mid)	modify(now<<1|1,mid+1,now_r,pos,val);
	M[now] = M[now<<1] * M[now<<1|1];
}
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout); 
	scanf("%lld",&n);
	for(int i=1; i<n; i++)	scanf("%lld",&w[i]);
	build(1,1,n-1);
	int q;scanf("%lld",&q);
	while(q--){
		int k,a;scanf("%lld%lld",&k,&a);
		w[k] = a;
		modify(1,1,n-1,k,a);
		matrix tmp;
		tmp.a[1][1] = INF,tmp.a[1][2] = 0;
		tmp.n = 1,tmp.m = 2;
		tmp = tmp * M[1];
		printf("%lld\n",tmp.a[1][1] * 2);
	} 
	return 0;
}

F.Communication Towers

题目描述:

有一张 \(n\) 个点 \(m\) 条边的无向图,第 \(i\) 个点只在第 \(L_i\) 到 \(R_i\) 这段时间出现。你需要对于每个点 \(i\),判断是否存在一个时刻 \(x\) ,使得 \(i\) 和 \(1\) 联通。

\(n\leq 2\times 10^5,m\leq 4\times 10^5\)

\(1\leq L_i\leq R_i\leq 2\times 10^5\)

题目分析:

(果然不愧为 Educational Round 就出这种典题)

首先 \(i\) 只会在 \([L_i,R_i]\) 出现,显然的想法就是线段树分治维护。

而询问连通性显然就是并查集啦,并查集的撤销也是可以做的,与 \(1\) 联通其实就是特殊处理一下 \(1\) 所在的连通块就可以了。

标签:146,10,Educational,le,题目,int,题解,times,leq
From: https://www.cnblogs.com/linyihdfj/p/17626991.html

相关文章

  • CF992E 题解
    CF992E题解传送门更好的阅读体验简化题意:单点修改,设序列的前缀和序列是$s_i$,查询是否存在一个$i$满足$a_i=s_{i-1}$。思路:观察满足条件的数的个数。在不考虑$0$的情况下,如果一个$a_i$满足条件,那么对于一个比他小的满足条件的数$a_j$,一定会有$a_j=s_{j-1}$,而$......
  • AtCoder Beginner Contest 314 A - Ex题解
    AtCoderBeginnerContest314A-3.14嗯,你可以用string存小数点后的...B-Roulette对于每一个金额,用个vector存pair<>存一个人赌了多少,以及是哪一个人。C-RotateColoredSubsequence每种数用个双向链表记下来。D-LOWER我们观察到,对于2,3操作,只有最后一次有用,且......
  • 杂题题解
    UOJ21缩进优化题目链接记\(M=\max(a_i)\)从反面考虑,考虑\(x\)让答案减小的量。即为$\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor\times(x-1)=(x-1)\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor$。只需要快速计算$S=\sum_{i=1}^n\lfloor\frac{a_i}{x}\rfloor$。可以......
  • ABC 314 F 题解
    原题传送门题意有n支队伍进行比赛,起初,第i支队伍只有选手i一个人。总共要进行n-1场比赛,每次给出p和q,意为让p所在的队伍与q所在的队伍进行比赛(数据保证此时p和q不在同一支队伍),设p所在的队伍有\(siz_p\)个人,q所在的队伍有\(siz_q\)个人,则此次比赛中p......
  • 【KMP】border 题解
    题目描述输入输出样例输入abaabaa样例输出17样例解释:f[2][a]=1f[3][a]=1f[4][a]=1f[4][b]=2f[5][a]=1f[5][b]=2f[6][a]=3f[7][a]=4f[7][b]=2以上为>0的f[][],求和=17数据范围限制这一篇同上一篇,都是从以前博客搬过来的,所以真的是......
  • 猴子拆房 题解
    题目描述输入输出样例输入【样例输入1】22345【样例输入2】3242513【样例输入3】6353417174241样例输出【样例输出1】3【样例输出2】0【样例输出3】10数据范围限制提示这个是我的,是我的QWQ,我没有转载,只是把以前的博客搬运......
  • 「题解注释」P7518 [省选联考 2021 A/B 卷] 宝石
    联合省选2021宝石题解-hezlik的博客-洛谷博客(luogu.com.cn)耗时:一晚上+半个上午代码注释:#include<bits/stdc++.h>usingnamespacestd;constintN=500000,C=21;intRi(){intx=0,y=1;charc=getchar();for(;c<'0'||c>'9';c=getchar())if......
  • CF452C 题解
    洛谷链接&CF链接题目简述有\(m\timesn\)张牌,有\(n\)个种类,每个种类有\(m\)张,现在抽一张放回,再抽一张,求这张牌与第一张抽出的牌种类相同的概率。思路本题是一道结论题,我们来推一下公式。首先需要特判一个点:只有\(1\)张牌,即\(n=m=1\),那么两次抽都会是这张牌,所......
  • acwing 116.飞行员兄弟 (算法竞赛进阶指南 p48 t1 ) 题解
    原题链接https://www.acwing.com/problem/content/description/118/题目描述“飞行员兄弟”这个游戏,需要玩家顺利的打开一个拥有16个把手的冰箱。已知每个把手可以处于以下两种状态之一:打开或关闭。只有当所有把手都打开时,冰箱才会打开。把手可以表示为一个4х4的矩阵,您可以......
  • IDEA/Android Studio的gradle控制台输出中文乱码问题解决
    原文地址:IDEA/AndroidStudio的gradle控制台输出中文乱码问题解决-Stars-One的杂货小窝在项目中,有使用到Gradle自定义脚本,会有些输出日志,但是输出中文就变成乱码了..本篇就介绍下解决方法乱码效果如下图所示步骤我是window系统,不知道其他系统会不会出现这个问题乱......