暑假连续codeforces刷题日记--day1

目录

前言

A. Sasha and Array Coloring

B. Long Long

C. Sum in Binary Tree

D. Apple Tree

E. Tracking Segments



前言

Codeforces Round 881 (Div. 3) VP (A - E)


A. Sasha and Array Coloring

        链接:https://codeforces.com/contest/1843/problem/A

        题意:给定一个数组A,你可以使用任意多种颜色,将数组A当中的每一个元素都染上一种颜色。定义一个颜色的价值为max(S)- min(S),S是所有这种颜色的元素的集合。让你输出所有颜色价值之和的最大值.

        思路:贪心,由题干可知,如果一种颜色的元素多于2个,那么取该元素的中间值,将其改成另外一种没有被用上的颜色,那么原颜色当中的最大值和最小值不会发生改变,答案也不会发生改变。同样的,如果一种颜色的元素为1个,那么可以和另外一个元素为1个的颜色组合,答案会增加。因此,每种颜色为2个的时候价值最大。所以答案为\sum_{n/2}^{n -1}ai - \sum_{0}^{n/2}ai

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
int cmp(int a,int b)
{
	return a<b;
}
LL qpow(LL a , LL b)//快速幂
{
	LL sum=1;
	while(b){
		if(b&1){
			sum=sum*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return sum;
}
void solve() 
{
	int n;
	cin>>n;
	int a[n];
	for(int i = 0 ; i  < n ; i++){
		cin>>a[i];
	}
	sort(a,a+n , cmp);
	int l = 0 , r = n - 1;
	int sum = 0;
	int cnt = 0;
	while(l < r){
		sum +=a[r] - a[l];
		r--;
		l++;
	}
	cout<<sum<<endl;
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

B. Long Long

               链接:https://codeforces.com/contest/1843/problem/B

               题意:给定一个数组A,你可以对其进行操作:对[l,r]范围内的{Al,Al+1,Al+1....Ar}进行乘以-1操作,求出最小操作数,使得整个数组的和最大,同时输出整个数组之和以及操作数的最小值

               思路:当整个数组的元素都为正数时,整个数组的和最大,同时0是否进行操作对于结果并不影响,因此只需要对于连续的非正数子序列进行操作即可

                


#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
int cmp(int a,int b)
{
	return a<b;
}
LL qpow(LL a , LL b)//快速幂
{
	LL sum=1;
	while(b){
		if(b&1){
			sum=sum*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return sum;
}
void solve() 
{
	int n;
	cin>>n;
	long long ans = 0;
	int flag = 0;
	int cnt = 0;
	for(int i = 0 ; i < n ; i ++){
		int k;
		cin>>k;
		if(k >= 0){
			if(k > 0)
			flag = 0;
			ans += k;
		}
		else 
		{
			if(flag == 1){
				ans -= k;
			}
			else{
				flag = 1;
				cnt++;
				ans -= k;
			}
		}
	}
	cout<<ans<<" "<<cnt<<endl;
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

 

C. Sum in Binary Tree

        链接:https://codeforces.com/contest/1843/problem/C

        题意:给定一颗完全二叉树,求出某个结点自己以及其所有祖宗的和并输出

         例如 8 这个结点,其Ans = 8 + 4 + 2 + 1 =15

        思路:根据完全二叉树的性质:Tr[u].father = Tr[u/2] 。可以从当前节点经过O(logn)的时间访问到根结点 。公式为:Value[n] = n + Value[N/2]

            


#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
int cmp(int a,int b)
{
	return a<b;
}
LL qpow(LL a , LL b)//快速幂
{
	LL sum=1;
	while(b){
		if(b&1){
			sum=sum*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return sum;
}
void solve() 
{
	long long n;
	cin>>n;
	long long ans=0;
	while(n){
		ans+=n;
		n/=2;
	}
	cout<<ans<<endl;
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

D. Apple Tree

      链接:https://codeforces.com/contest/1843/problem/D

      题意:给定一棵树(其中根节点为1),树上面有两颗苹果.你可以摇晃这棵树,每次摇晃后,如果当前这个苹果所在的结点有子节点,那么苹果会随机掉落到任意一个子节点之上,如果没有子节点,那么苹果则会掉落到地上,求出这两个苹果最终所在结点的序列数量之和.

                

                如果苹果一开始在{1,4}这两个结点之上,那么最终两个苹果可能掉落的序列为{4,4},{5,4}两种,因此答案为2.

                同样的,如果苹果在{2,3},那么最终可能的序列为{4,4},{4,5},{5,4},{5,5},因此答案为5.

        思路:利用DFS或者DP,求出所有结点最终的叶子节点数量。状态转移公式:当前节点为子节点则 DP[N] = 1,如果当前节点不是子节点则DP[N] = \sum DP[N.child]

        代码:


#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
const LL maxn = 4e05+7;
const LL N=2e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
int cmp(int a,int b)
{
	return a<b;
}
LL qpow(LL a , LL b)//快速幂
{
	LL sum=1;
	while(b){
		if(b&1){
			sum=sum*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return sum;
}
vector<int>tr[N];
LL sum[N];
void init(int root , int fa){
	if(root != 1 && tr[root].size() == 1){
		sum[root] = 1;
		return;
	}
	for(int i = 0 ; i < tr[root].size() ; i ++){
		int k = tr[root][i];
		if(k != fa){
			init(k , root);
		}
	}
}
int cntchild(int root , int fa){
	if(sum[root] != -1)
		return sum[root];
	else{
		int cnt = 0;
		for(int i = 0 ; i <(int)tr[root].size() ; i ++){
			int k = tr[root][i];
			if(k != fa)
				cnt += cntchild(k,root);
		}
		sum[root] = cnt;
		return sum[root];
	}
}
void solve() 
{
	int n;
	cin>>n;
	for(int i = 0 ; i <= n ; i ++)
		sum[i] = -1;
	for(int i = 1 ; i < n ; i ++){
		int a,b;
		cin>>a>>b;
		tr[a].pb(b);
		tr[b].pb(a);
	}
	init(1,1);
	cntchild(1,1);
	int m;
	cin>>m;
	for(int i = 0 ; i < m  ; i++ ){
		int a,b;
		cin>>a>>b;
//		cout<<sum[a]<<" "<<sum[b]<<endl;
		cout<<(LL)sum[a]*sum[b]<<endl;
	}
	long long ans = 0;
	for(int i = 0 ; i <= n ; i ++){
		tr[i].clear();
	}
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

E. Tracking Segments

        链接:https://codeforces.com/contest/1843/problem/E

        题意:给定一个长度为n的全零数组a,同时给了你m个线段,线段[l,r]代表了数组[al,al+1...ar]。定义如果线段[l,r]当中1的数量大于0的数量,那么这个线段被称作美丽的。下面给了你q个操作,每个操作有一个数字x(1\leq x\leq n),将ax变为1。问你最少操作多少次时,这m个线段当中能够出现美丽的线段。输出这个最少操作数,如果不存在,则输出-1.

        思路:对于操作而言,单点修改和区间查询,可以利用前缀和来实现。而要求出最少操作数时,可以利用二分法来找到这个最小值.

        代码:

// Problem: E. Tracking Segments
// Contest: Codeforces - Codeforces Round 881 (Div. 3)
// URL: https://codeforces.com/contest/1843/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
pl st[N];
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
int cmp(int a,int b)
{
	return a<b;
}
LL qpow(LL a , LL b)//快速幂
{
	LL sum=1;
	while(b){
		if(b&1){
			sum=sum*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return sum;
}
int sum[N];
int a[N];
int change[N];
void init(int n){
	for(int i = 0 ; i <= n ; i++){
		sum[i] = 0;
		a[i] = 0;
	}
}
int flag = false;
int check(int mid , int n , int m){
	init(n);
	for(int i = 1 ; i <= mid ; i ++){
		a[change[i]] = 1;
	}
	for(int i = 1 ; i <= n ; i++){
		sum[i] = sum[i-1] + a[i];
	}
	for(int i = 1 ; i <= m ; i++){
		int len = st[i].y - st[i].x + 1;
		int cnt = sum[st[i].y] - sum[st[i].x - 1];
		if(cnt*2 > len){
			flag = true;
			return 1;	
		}
	}
	return 0;
}
void solve() 
{
	int n,m;
	cin>>n>>m;
	for(int i = 1 ; i <= m ; i++){
		cin>>st[i].x>>st[i].y;
	}
	int q;
	cin>>q;
	for(int i = 1 ; i <= q; i ++){
		cin>>change[i];
	}
	int l = 1 , r = q;
	flag = false;
	while(l < r){
		int mid = (l + r)>>1;
		if(check(mid , n , m)){
			r = mid;
		}
		else{
			l = mid + 1;
		}
	}
	check(q,n,m);//q次未被判断到
	if(flag)
		cout<<l<<endl;
	else
		cout<<-1<<endl;
}            
int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout.precision(10);
    int t=1;
	cin>>t;
    while(t--)
    {
    	solve();
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值