2021.8.27夏令营阶段测试总结

Hello,大家好!

我是蒟亦先生!

温馨提示:请各位奆奆们洁身自好,请勿COPY!


题解:

浇花


代码实现+解析

首先,我们对题目做一个分析:

前面的一堆废话

关键句:“浇完m次花以后,最矮的花的最大高度。”——这很明显是二分的标志。

我们二分最矮的花的高度,然后用O(n)的时间复杂度检查是否可行。

只要浇花的区间固定了,那么顺序对答案没有影响。

因此,从第1株到第n株扫描一遍,每次发现一株高度低于mid的花,就以这株花为区间的左端点,设这株花再长y厘米可以达到mid,就把以这株花为左端点的区间内的所有花高度加上y。

可是,每次浇花时把整个区间遍历一遍,时间复杂度还是有点高。

于是,我们就要用到一个差分的思想。

我们先设差分数组为num,

如果区间[l,r]的值要全部加上y,则num[l]+=y,num[r+1]-=y.


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1e5+5;
ll n,m,w,sum,ans,i,j,h[N],num[N*2];
bool check(ll mid)
{
	ll i=1,j,cnt=0,x=m,y;
	memset(num,0,sizeof(num));
	while(i<=n)
	{
		while(h[i]+cnt>=mid&&i<=n)
		{
			cnt-=num[++i];
		}
		if(i>n)
		{
			return 1;
		}
		y=mid-h[i]-cnt;
		if(y>x)
		{
			return 0;
		}
		num[i+w]=y;
		cnt+=y;
		x-=y;
		cnt-=num[++i];
	}
	return 1;
}
int main()
{
	ll l=9e9,r=-1,mid;
	cin>>n>>m>>w;
	for(i=1;i<=n;i++)
	{
		cin>>h[i];
		l=min(l,h[i]);
		r=max(r,h[i]);
	}
	r+=m;
	while(l<=r)//二分答案 
	{
		mid=(l+r)/2;
		if(check(mid))//判断高度低于mid的花 
		{
			l=mid+1;
			ans=mid;
		}
		else
		{
			r=mid-1;
		}
	}
	cout<<ans;
	return 0;
}

读书


代码实现+解析

根据题意,我们可以考虑第i次拿书,那么前面的i-1次拿的书一定都会产生贡献。

换句话说,这里的贡献我们是改变不了的,它是个定值,所以我们只能最小化初始序列对操作所产生的贡献。

因此,初始序列就是每本书第一次被拿出来的顺序。

最后得到初始序列直接模拟就做好了。


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1e4;
ll n,m,i,j,cnt,w[N],a[N],b[N*2],bj[N];
int main()
{
	cin>>n>>m;
	ll cnt=m,l=m+1,ans=0;
	for(i=1;i<=n;i++)
	{
		cin>>w[i];
	}
	for(i=1;i<=m;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<=m;i++)
	{
		if(bj[a[i]])
		{
			continue;
		}
		b[++cnt]=a[i];
		bj[a[i]]=1;
	}
	for(i=1;i<=m;i++)
	{
		j=l;
		while(a[i]!=b[j])
		{
			ans+=w[b[j++]];
		}
		b[--l]=a[i];
		b[j]=0;
	}
	cout<<ans;
	return 0;
}

奶牛野餐


代码实现+解析

So easy!

大家根据题目应该都能想到思路——

先从每个奶牛所在的地方开始访问,每个节点若能访问到,则对应的次数+1,如果节点次数=奶牛数,则符合题目要求,ans++,最后输出ans即可。


#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=1e4+5;
ll lk[maxn],ans,ltp,t1[maxn],f[maxn],h[maxn];//f数组记录节点状态,h数组每次处理f数组的结果 
struct zjy
{
	ll y,nxt;
}e[maxn];
struct edge//输入时存边 
{
	ll x,y;
}a[maxn];
void add(ll x,ll y)
{
	e[++ltp]={y,lk[x]};
	lk[x]=ltp;
}
void dfs(ll x)
{
	if(!f[x])
	{
		f[x]=1;
		for(ll i=lk[x];i>=1;i=e[i].nxt)
		{
			dfs(e[i].y);
		}
	}
}
int main()
{
	ll i,j,k,n,m;
    cin>>k>>n>>m;
    for(i=1;i<=k;i++)
    {
    	cin>>t1[i];
    }
    for(i=1;i<=m;i++)
    {
    	cin>>a[i].x>>a[i].y;
    }
    for(i=1;i<=m;i++)
    {
    	add(a[i].x,a[i].y);
    }
    for(i=1;i<=k;i++)
    {
    	if(t1[i])
    	{
    		dfs(t1[i]);
			for(j=1;j<=n;j++)
			{
				if(f[j])
				{
					h[j]++;
				}
			}
			memset(f,0,sizeof(f));
    	}
    }
    for(i=1;i<=1005;i++)
    {
    	if(h[i]==k)
    	{
    		ans++;
    	}
    }
    cout<<ans;
    return 0;
}

谢谢各位奆奆!

题解制作不易,望能用心思考

如有疑问,欢迎提出问题一起讨论!

本章完

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值