Codeforces Round #661(CF1399)题解

Solution

A

可以发现,我们可以从小的开始向上推平,例如对于序列 1   1   2   3   3   4 1\ 1\ 2\ 3\ 3\ 4 ,我们可以先在 1 , 1 1,1 中删掉一个 1 1 ,然后在 1 , 2 1,2 中删掉一个 1 1 ,在 2 , 3 2,3 中删掉一个 2 2 ……在 3 , 4 3,4 中删掉一个 3 3 ,以此类推,这样删数毫无疑问是最佳选择。

于是,我们模拟即可,判断最终能否只剩下一个数。同时也可以直接判断,排序后是否相邻两个数之差在 1 1 及以内

B

首先,我们先要想好把 A A 数列和 B B 数列分别改成什么数,显然都是这两个数列的最小值。

于是,考虑对于两个数 x , y x,y ,现在分别把它们改成 a , b a,b 需要的最少操作次数。我们需贪心地先尽可能多地一起减 1 1 ,再对于一个减 1 1 ,即最少操作次数为 m a x ( x a , y b ) max(x-a,y-b)

故答案为 i = 1 n m a x ( a i x , b i y ) \sum_{i=1}^n max(a_i-x,b_i-y) ,其中 x x y y 分别是 A , B A,B 序列的最小值。

C

直接枚举显然超时,考虑开桶 v i v_i 记录下了 i i 出现的次数。

我们首先把桶给建出来,然后枚举对于每一个 s s ,最多能够参加的组数。此时答案为

i = 1 s 1 m i n ( v i , v s i ) \sum_{i=1}^{s-1} min(v_i,v_{s-i})

注意, i = s i i=s-i 的时候,它对答案的贡献是 v i 2 \lfloor \frac {v_i} 2 \rfloor 而非 m i n ( v i , v s i ) min(v_i,v_{s_i})

时间复杂度 O ( t n 2 ) O(tn^2)

D

一道对顶栈的好题(全网貌似就本蒟蒻这么做吧)。

两个栈,第一个栈表示出所有结尾的数为 0 0 的子序列的编号,第二个栈记录下所有结尾的数为 1 1 的子序列的编号

如果这个值是 0 0 ,那么尝试拿它拼在第二个栈中某个子序列的后面,并让拼后的子序列滚出第二个栈,跳进第一个栈里面。如果第二个栈为空,则新开一个子序列并放在第一个栈里面,答案加一

如果这个值是 1 1 则同理。

此时时间复杂度为 O ( n ) O(n) 。注意对顶栈可以用数组模拟,所以不要担心不会用 S T L STL s t a c k stack 啦。

E1

首先,我们思考这样一个问题: 对于一棵带权树,求出根节点到每个叶节点的距离之和。

首先,把边权转为点权,每个点的点权为其与其父亲的边权。然后,假设某个节点的子树中有 k k 个叶子,那么该节点的点权对答案的贡献次数就是 k k 次。算某个节点的子树中的叶节点个数显然可以通过递推预处理得到。若第 i i 个节点的点权为 a i a_i ,它的子树中叶节点的个数为 l i l_i ,则这个题目的答案为 i = 1 n a i × l i \sum_{i=1}^n a_i×l_i

回到原题,发现这里的 a i a_i 是可变的。可以发现,我们每次都贪心地选择这样一个节点,使得将它进行操作后答案减少得最多,直到答案到达规定范围为止。每次的贪心最优状态(将它进行操作后答案减少得最多)可以用优先队列维护。

注意, a i × l i a_i×l_i 在对 i i 进行操作后, a i × l i a_i×l_i 变小的值应当直接计算为 a i × l i ( a i 2 ) l i a_i×l_i-(\lfloor \frac {a_i} 2\rfloor)l_i ,绝对不是 a i × l i 2 \lfloor \frac {a_i×l_i} 2 \rfloor ,本蒟蒻因此 W A WA 了一次。

E2

可以发现,现在改每条边的代价变得不同了。

首先,我们需要考虑,这题我们要求的是代价的最小值,但边的代价的情况有且仅有两个,即 1 1 2 2

对于相同代价的边,我们均按 E 1 E1 的方式做,找出对于该类代价的边,得到某种总权值的代价的最小值,显然可以通过 E 1 E1 的方法得到。得到了这些之后,我们分别考虑: 通过改代价为 1 1 的边,共消耗了 k k 的代价且当前总权值为 w w ,那么我们需要找到改代价为 2 2 的边的总权值 w 2 w_2 与其代价 k 2 k_2 ,使得 w 2 + w S w_2+w≤S k 2 + k k_2+k 的值最小。由于代价有单调性,我们可以双指针来扫。

例如,对于价值为 1 1 的边,权值分别是 10 , 12 , 15 10,12,15 l l 值分别是 1 , 1 , 1 1,1,1 ,则有:

37 : 0 37: 0 (得到权值为 37 37 的情况需要 0 0 的代价)
29 : 1 29: 1 (得到权值为 29 29 的情况需要 1 1 的代价)
23 : 2 23: 2
18 : 3 18:3
14 : 4 14:4
11 : 5 11:5
8 : 6 8:6
……

另外,代价为 2 2 的边的权值为 3 , 4 3,4 l l 值分别是 1 , 1 1,1 ,则有:

7 : 0 7:0
5 : 1 5:1
3 : 2 3:2
2 : 3 2:3
……

此时,假设 s = 25 s=25 ,那么,我们直接考虑,用 23 23 2 2 配对, 18 18 7 7 配对……最终用双指针得到答案。

总时间复杂度为 O ( n i = 1 n l o g 2 a i n ) O(n \sum_{i=1}^n log_2 a_in)

Code

#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;

int t,n;
int a[200005],b[200005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		for (int i=1;i<=n;i++)  cin>>a[i];
		for (int i=1;i<=n;i++)  cin>>b[i];
		
		int mina=inf,minb=inf,ans=0;
		for (int i=1;i<=n;i++)  mina=min(mina,a[i]);
		for (int i=1;i<=n;i++)  minb=min(minb,b[i]);
		for (int i=1;i<=n;i++)  ans+=max(a[i]-mina,b[i]-minb);
		cout<<ans<<endl;
	}
	return 0;
}

B

#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;

int t,n;
int a[200005],b[200005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		for (int i=1;i<=n;i++)  cin>>a[i];
		for (int i=1;i<=n;i++)  cin>>b[i];
		
		int mina=inf,minb=inf,ans=0;
		for (int i=1;i<=n;i++)  mina=min(mina,a[i]);
		for (int i=1;i<=n;i++)  minb=min(minb,b[i]);
		for (int i=1;i<=n;i++)  ans+=max(a[i]-mina,b[i]-minb);
		cout<<ans<<endl;
	}
	return 0;
}

C

#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;

int t,n,x;

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		
		int a[1005]={0};
		for (int i=1;i<=n;i++)
		{
			cin>>x;
			a[x]++;
		}
		int ans=0;
		for (int i=1;i<=100;i++)
		{
			int now=0;
			for (int j=1;j<=i-1;j++)
			{
				if (j!=i-j)  now+=min(a[j],a[i-j]);
				else now+=(a[j]/2)*2;
			}
			ans=max(ans,now);
		}
		cout<<ans/2<<endl;
	}
	return 0;
}

D

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n,len0=0,len1=0,len=0,maxv=0;
int a[200005],ans[200005],x[200005],y[200005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		len=0,len0=0,len1=0,maxv=0;
		for (int i=1;i<=n;i++)
		{
			char x;
			cin>>x;
			a[i]=x-'0';
		}
		for (int i=1;i<=n;i++)
		{
			int now=a[i]^1;
			if (now==0)
			{
				if (len0>=1)
				{
					ans[i]=x[len0];
					len1++;
					y[len1]=x[len0];
					len0--;
				}
				else
				{
					len++,len1++;
					y[len1]=len;
					ans[i]=len;
				}
			}
			else
			{
				if (len1>=1)
				{
					ans[i]=y[len1];
					len0++;
					x[len0]=y[len1];
					len1--;
				}
				else
				{
					len++,len0++;
					x[len0]=len;
					ans[i]=len;
				}
			}
			maxv=max(maxv,ans[i]);
		}
		cout<<maxv<<endl;
		for (int i=1;i<=n;i++)  cout<<ans[i]<<' ';
		cout<<endl;
	}
	return 0;
}

E1

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n,u,v,w,tot,s,ans=0,cnt=0;
int head[500005],l[200005];

struct edge
{
	int next;
	int to;
	int dis;
}e[500005];

struct node
{
	int rt;
	int num;
}a[200005];

inline void dfs(int now,int fath)
{
	for (int i=head[now];i;i=e[i].next)
	{
		if (e[i].to!=fath)
		{
			a[e[i].to].rt=e[i].to;
			a[e[i].to].num=e[i].dis;
			dfs(e[i].to,now);
		}
	}
}

inline void dfs2(int now,int fath)
{
	int flag=1;
	for (int i=head[now];i;i=e[i].next)
	{
		if (e[i].to!=fath)
		{
			flag=0;
			dfs2(e[i].to,now);
			l[now]+=l[e[i].to];
		}
	}
	if (flag==1)  l[now]=1;
}

inline void add_edge(int u,int v,int w)
{
	cnt++;
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].next=head[u];
	head[u]=cnt;
}

bool operator < (const node &x,const node &y)
{
	int nowx=x.num*l[x.rt]-(x.num/2)*l[x.rt];
	int nowy=y.num*l[y.rt]-(y.num/2)*l[y.rt];
	return nowx<nowy;
}

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n>>s;
		tot=0,ans=0,cnt=0;
		for (int i=1;i<=n;i++)  l[i]=0;
		for (int i=1;i<=2*n;i++)
		{
			head[i]=0;
			e[i].next=e[i].dis=e[i].to=0;
		}
		for (int i=1;i<n;i++)
		{
			cin>>u>>v>>w;
			add_edge(u,v,w);
			add_edge(v,u,w);
		}
		dfs(1,0);
		dfs2(1,0);
	
		for (int i=1;i<=n;i++)  tot+=a[i].num*l[i];
		std::priority_queue<node,vector<node> > q;
		
		for (int i=1;i<=n;i++)  q.push(a[i]);
		while (tot>s)
		{
			node now=q.top();
			q.pop();
			tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
			now.num/=2;
			q.push(now);
			ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

E2

#include <bits/stdc++.h>
#define int long long
using namespace std;
 
int t,n,u,v,w,w2,tot,s,cnt=0,posl=0,posr=0,nowcost=0,pl,pr,ans,nowtot=0;
int head[500005],l[200005],qwq[200005];
 
struct edge
{
	int next;
	int to;
	int dis;
	int opt;
}e[500005];
 
struct node
{
	int rt;
	int num;
}a[2000005];
 
struct left_graph
{
	int num;
	int cost;
}le[2000005];
 
struct right_graph
{
	int num;
	int cost;
}ri[2000005];
 
inline void dfs(int now,int fath)
{
	for (int i=head[now];i;i=e[i].next)
	{
		if (e[i].to!=fath)
		{
			a[e[i].to].rt=e[i].to;
			a[e[i].to].num=e[i].dis;
			qwq[e[i].to]=e[i].opt;
			dfs(e[i].to,now);
		}
	}
}
 
inline void dfs2(int now,int fath)
{
	int flag=1;
	for (int i=head[now];i;i=e[i].next)
	{
		if (e[i].to!=fath)
		{
			flag=0;
			dfs2(e[i].to,now);
			l[now]+=l[e[i].to];
		}
	}
	if (flag==1)  l[now]=1;
}
 
inline void add_edge(int u,int v,int w,int w2)
{
	cnt++;
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].next=head[u];
	e[cnt].opt=w2;
	head[u]=cnt;
}
 
bool operator < (const node &x,const node &y)
{
	int nowx=x.num*l[x.rt]-(x.num/2)*l[x.rt];
	int nowy=y.num*l[y.rt]-(y.num/2)*l[y.rt];
	return nowx<nowy;
}
 
signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n>>s;
		tot=0,cnt=0,posl=0,posr=0,nowcost=0,ans=1e18+7,nowtot=0;
		for (int i=1;i<=n;i++)  l[i]=0;
		for (int i=1;i<=2*n;i++)
		{
			head[i]=0;
			e[i].next=e[i].dis=e[i].to=0;
		}
		for (int i=1;i<n;i++)
		{
			cin>>u>>v>>w>>w2;
			add_edge(u,v,w,w2);
			add_edge(v,u,w,w2);
		}
		dfs(1,0);
		dfs2(1,0);
		std::priority_queue<node,vector<node> > q;
		
		for (int i=1;i<=n;i++)  nowtot+=a[i].num*l[i];
		if (nowtot<=s)
		{
			cout<<0<<endl;
			continue;
		}
		for (int i=1;i<=n;i++)
		{
			if (qwq[i]==1)  q.push(a[i]),tot+=a[i].num*l[i];
		}
		while (tot>0)
		{
			if (tot<=s)
			{
				le[++posl].num=tot;
				le[posl].cost=nowcost;
			}
			node now=q.top();
			q.pop();
			tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
			now.num/=2;
			q.push(now);
			nowcost++;
		}
		le[++posl].num=tot;
		le[posl].cost=nowcost;
		while (!q.empty())  q.pop();
		nowcost=0;
		
		for (int i=1;i<=n;i++)
		{
			if (qwq[i]==2)  q.push(a[i]),tot+=a[i].num*l[i];
		}
		while (tot>0)
		{
			if (tot<=s)
			{
				ri[++posr].num=tot;
				ri[posr].cost=nowcost;
			}
			node now=q.top();
			q.pop();
			tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
			now.num/=2;
			q.push(now);
			nowcost+=2;
		}
		ri[++posr].num=tot;
		ri[posr].cost=nowcost;
		pl=1,pr=posr;
		if (posl==0) 
		{
			cout<<ri[1].cost<<endl;
			continue;
		}
		if (posr==0)
		{
			cout<<le[1].cost<<endl;
			continue;
		}
		for (pl=1;pl<=posl;pl++)
		{
			while (le[pl].num+ri[pr].num<=s&&pr>1)  pr--;
			if (le[pl].num+ri[pr].num>s)  pr++;
			
			ans=min(ans,le[pl].cost+ri[pr].cost);
		}
		cout<<ans<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/107848594