目录
前言
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个的时候价值最大。所以答案为
#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
思路:根据完全二叉树的性质: 。可以从当前节点经过O(logn)的时间访问到根结点 。公式为:
#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,求出所有结点最终的叶子节点数量。状态转移公式:当前节点为子节点则 ,如果当前节点不是子节点则
代码:
#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个操作,每个操作有一个数字,将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;
}