Codeforces Round #381 (Div. 2)

题目链接
A A
题意
小A有 n n 个本子,现在他要再买 k k 本来使的 4     n + k 4\ | \ n+k ,现在商店里有三种零售模式,花 a a 元买一本,花 b b 元买两本,话 c c 元买3本。问最少花费多少可以满足要求。
思路
思路要清晰才行。
现在想最少差多少本满足要求呢? n % 4 n\% 4 代表除4的余数,那么
d = 4 n % 4 d=4-n\%4 代表着最少差多少本可以满足要求。
d = 4 d=4 ,意味着 4     n 4 \ | \ n ,花费为0.
d = 3 d=3 ,差3本,可以花 c c 元买3本,也可以买3个1本,即 3 a 3\cdot a ,或者买一个一本和一个两本,即 a + b a+b 。除此之外没有别的买法了,去 m i n min 即可。
d = 2 d=2 ,差两本,可以买一个两本,花费 b b ,也可以花费 2 a 2\cdot a ,这是很显然的,然后也可以买6本,因为 6 % 4 = 2 6 \% 4=2 ,这六本可以有很多种构成方式,但是最优的是两个三本,因为如果再加上加1本或者两本的情况都没有前面的情况优,即花费 2 c 2*c
d = 1 d=1 ,这里面有种情况可能会忽略。
可以花费 a a 也可以买5本,因为 5 % 4 = 1 5\%4=1 ,花费 b + c b+c ,还可以买9本,花费 3 c 3*c
综上

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define ll long long
const ll N = 2e5+10;
int main(){
   ll n,a,b,c;
   cin >> n >> a >> b >>c;
   if(n % 4 == 0) return cout << 0,0;
   ll d = 4 - n % 4;
   if(d == 1) {
      ll q = a;
      ll w = 3 * c;
      ll e = b + c;
      cout << min(q,min(w,e));
   }
   else if(d == 2){
      ll q = b;
      ll w = 2 * a;
      ll e = 2 * c;
      cout<<min(q,min(w,e));
   }
   else {
      ll q = c;
      ll w = 3 * a;
      ll e = a + b;
      cout<<min(q,min(w,e));  
   }
}

B B
题意小h的妈妈给她n盆花,每朵花都有一个喜悦值,然后小h的妈妈给她m个区间,然后让小h任意选择使得小h获得的喜悦值值正。
思路
这个题意的解释有误导作用。如果深入思考会发现,其实没选择一个区间其实增加的就是这个区间的区间和。所以我们选择区间和为正的区间累加即可。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define ll long long
const ll N = 2e5+10;
int ans[1000];
int main(){
   int n,m;
   cin >> n >> m;
   for(int i = 1;i <= n;++i) cin >> ans[i];
   ll sum = 0;
   for(int i = 1;i <= m;++i){
      ll l,r;
      cin >> l >> r;
      ll num = 0;
      for(int j = l;j <= r;++j) num += ans[j];
      num = max(num,0LL);
      sum += num;
   }
   cout<<sum;
}

C C
题意
这个区间有n个数字,然后有m个字区间,定义每个子区间mex为没有出现在区间中的最小的非负整数。现在让你构造出这个数组,并且尽量使得所有子区间的最小的mex值最大。
思路:
比较好想的是满足要求的mex值就是最小区间的长度,如何构造这个数组是不大好想的。我们可以这样想,我们先满足最小区间条件成立,假如最小的区间长度为 l l ,那么这个区间的数值可以为 0 , 1 , 2 , 3... , l 1 0,1,2,3...,l-1 。我们要数组中所有区间为 l l 的区间都满足,那么这m个区间也肯定满足,最后构造出数组方法为 0 , 1 , 2 , 3 , l 1 , 0 , 1 , 2....... 0,1,2,3,l-1,0,1,2....... ,保证m个区间任意一个区间都是mex就足够了。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const ll N = 2e5+10;
int main(){
   int n,m;
   cin >>n >>m;
   int d = INF;
   for(int i = 1;i <= m;++i){
      int l,r;
      cin >> l >> r;
      d = min(d,r-l);
   }
   d ++;
   cout<<d<<endl;
   int cnt = 0;
   for(int i = 1;i <=n;++i){
      cout<<(cnt++) % d<<' '; 
   }
}

D
题意
一棵树,树上有 n n 个点,标号为1~n,且1是树根。然后每个点都有一个值 a [ i ] a[i] ,每条边也有一个权值 w w ,然后让你输出每个可以控制点的数目。(比如 u u 控制 v v ,即树上 u > v u->v 的权值 d [ u , v ] < = a [ v ] d[u,v]<=a[v]
思路
首先比较好想的是暴力的方法。
预处理深度遍历树根到所有节点的权值,然后对每个点进行 d f s dfs ,结果T。
我们在脑海中想象下遍历这棵树的过程,在DFS过程中在栈中总会呈现一条树根 到 子节点的路径,我们在这条路径上进行二分查找这条路径上 满足条件的 距当前节点最远点(也就是最靠根的节点),然后这一段路径区间都可以加1,区间修改,我们可以差分来缩减时间复杂度,只不过这是在树上差分。
有一点需要注意,差分时注意区间首尾别颠倒!

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const ll N = 2e5+10;
ll d[N];//到根节点的距离
ll a[N];
int head[N],tot;
struct Edge{
   int next;
   int to;
   ll dis;
}edge[N<<2];
inline void add(int from,int to,ll dis){
   edge[++tot].next = head[from];
   edge[tot].to = to;
   edge[tot].dis = dis;
   head[from] = tot;
}
vector<int> T;//记录路径
int c[N];//答案数组
int pre[N];//记录前驱
void dfs(int root){
	int l = 0,r = T.size() - 1;
	while(l < r){
		int mid = l + r >> 1;
		if(d[root] - d[T[mid]] <= a[root]) r = mid;
		else l = mid + 1;
	}
	if(T.size() != 0&&d[root] - d[T[r]] <= a[root]){
		c[pre[root]] ++;
		c[pre[T[r]]] --;
	}
	T.push_back(root);
	for(int i = head[root];~i;i = edge[i].next){
		int  y = edge[i].to;
		ll dis = edge[i].dis;
		d[y] = d[root] + dis;
		dfs(y);
	}
	T.pop_back();
}
void DFS(int x){
	for(int i = head[x];~i;i = edge[i].next){
		int y = edge[i].to;
		DFS(y);
		c[x] += c[y];
		
	}
}
int main(){
   memset(head,-1,sizeof head);
   int n;
   scanf("%d",&n);
   for(int i = 1;i <= n;++i) scanf("%lld",&a[i]);
   int u;ll dis;
   for(int i = 2;i <= n;++i){
      scanf("%d%lld",&u,&dis);
      add(u,i,dis);
	  pre[i] = u;
      //add(i,u,dis);
   }
   dfs(1);
   DFS(1);
   for(int i = 1;i <= n;++i) cout<<c[i]<<' ';

}
发布了636 篇原创文章 · 获赞 27 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43408238/article/details/104105438
今日推荐