P5016 [NOIP2018 普及组] 龙虎斗 题解

提前声明:本题解不提供快捷目录,请耐心看完(一定要看到最后呀!!!)

懒得再写一遍题目了,直接看原题 

题目链接

其实这道题暴力枚举每个点就可以,话不多说,先上代码

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

int n,m,p1,p2,s1,s2;
int l=0,h=0;//l表示龙的势力,r表示虎的势力 
void place()//直接暴力就行 
{
	int cj=abs(l-h);//cj表示差距,龙虎势力值之的绝对值 
	if(l>h)//龙的势力大于虎的势力 
	{
		for(int i=n;i>m;i--)//暴力枚举 
		{
			int hh=h+s2*(i-m);//不能直接改h,用hh代替 
			if(cj>abs(hh-l))//判断两方势力差距是否更小 
			{
				p2=i;
				cj=abs(hh-l);//这里注意刷新差距 
			}
		}
		return;
	}
	if(h>l)//虎的势力大于龙的势力 
	{
		for(int i=1;i<m;i++)//暴力枚举
		{
			int ll=l+s2*(m-i);
			if(cj>abs(ll-h))
			{
				p2=i;
				cj=abs(ll-h);
			}
		}
		return;
	}
}
int main()
{
	cin>>n;
	int a[n+5];//可以这样用变量定义数组 ,a存储每个点工兵数量 
	for(int i=1;i<=n;i++)
		cin>>a[i];
	cin>>m>>p1>>s1>>s2;
	for(int i=1;i<m;i++) 
		l+=(m-i)*a[i];//求龙的势力
	for(int i=n;i>m;i--)
		h+=(i-m)*a[i];//求虎的势力
	if(p1<m)//s1名工兵降落在龙方阵营 
		l+=(m-p1)*s1;
	if(p1>m)//s1名工兵降落在虎方阵营 
		h+=(p1-m)*s1;
	//否则降落在m点上,不用管
	p2=m;//初始p2值为m 
	place();
	cout<<p2;
	return 0;
}

然后就挂了五个点......

到底是哪里出了问题

其实代码没问题,原因是没开longlong.......

虽然一个数int存的下,但加起来会超过int(在1e18~ 9e18之间,炸int了)

于是,开成longlong就过了,(我懒得一个一个改,全给他用替换改longlong了)

满分AC代码了解一下:(不要抄完代码就划走,后面的东西很重要)

#include<bits/stdc++.h>
#define lll long long //因为后面有定义的ll,所以只能define成lll(懒得打那么多遍long long) 
using namespace std;

lll n,m,p1,p2,s1,s2;
lll l=0,h=0;//l表示龙的势力,r表示虎的势力 
void place()//直接暴力就行 
{
	lll cj=abs(l-h);//cj表示差距,龙虎势力值之的绝对值 
	if(l>h)//龙的势力大于虎的势力 
	{
		for(lll i=n;i>m;i--)//暴力枚举 
		{
			lll hh=h+s2*(i-m);//不能直接改h,用hh代替 
			if(cj>abs(hh-l))//判断两方势力差距是否更小 
			{
				p2=i;
				cj=abs(hh-l);//这里注意刷新差距 
			}
		}
		return;
	}
	if(h>l)//虎的势力大于龙的势力 
	{
		for(lll i=1;i<m;i++)//暴力枚举
		{
			lll ll=l+s2*(m-i);
			if(cj>abs(ll-h))
			{
				p2=i;
				cj=abs(ll-h);
			}
		}
		return;
	}
}
int main()
{
	cin>>n;
	lll a[n+5];//可以这样用变量定义数组 ,a存储每个点工兵数量 
	for(lll i=1;i<=n;i++)
		cin>>a[i];
	cin>>m>>p1>>s1>>s2;
	for(lll i=1;i<m;i++) 
		l+=(m-i)*a[i];//求龙的势力
	for(lll i=n;i>m;i--)
		h+=(i-m)*a[i];//求虎的势力
	if(p1<m)//s1名工兵降落在龙方阵营 
		l+=(m-p1)*s1;
	if(p1>m)//s1名工兵降落在虎方阵营 
		h+=(p1-m)*s1;
	//否则降落在m点上,不用管
	p2=m;//初始p2值为m 
	place();
	cout<<p2;
	return 0;
}

哦,对了,你们有没有注意一个点

题目中说,如果存在多个编号同时满足最优,取最小的编号

但为什么我并没有特意避这个坑点而AC了呢

我们再来回顾程序:

if(l>h)//龙的势力大于虎的势力 
	{
		for(lll i=n;i>m;i--)//暴力枚举 
		{
			lll hh=h+s2*(i-m);//不能直接改h,用hh代替 
			if(cj>abs(hh-l))//判断两方势力差距是否更小 
			{
				p2=i;
				cj=abs(hh-l);//这里注意刷新差距 
			}
		}
		return;
	}
	if(h>l)//虎的势力大于龙的势力 
	{
		for(lll i=1;i<m;i++)//暴力枚举
		{
			lll ll=l+s2*(m-i);
			if(cj>abs(ll-h))
			{
				p2=i;
				cj=abs(ll-h);
			}
		}
		return;
	}

这是程序的主枚举部分

我们先看龙的,i=1;i<m;i++;

也就是说从小到大依次枚举,并且cj>abs(ll-h)这块我没有加等号,则程序就自动判定小者优先,因为先判定了小的,后面与其相等的就判不上(这里再看不懂为什么就有点过分了)

再看虎的,i=n;i>m;i--,是从大到小判......

呵呵,是的,我似乎并没有避开这个坑点,但数据他没坑我呀,也就蒙混过关了(不要嫌我嘴欠:P)

但为了程序的严谨性,为了我们的正义感,我决定了:

#include<bits/stdc++.h>//就不加注释了,注释看前面
#define lll long long
using namespace std;

lll n,m,p1,p2,s1,s2;
lll l=0,h=0;
void place()
{
	lll cj=abs(l-h);
	if(l>h)
	{
		for(lll i=m+1;i<=n;i++)//这里改了哟
		{
			lll hh=h+s2*(i-m);
			if(cj>abs(hh-l))
			{
				p2=i;
				cj=abs(hh-l);
			}
		}
		return;
	}
	if(h>l) 
	{
		for(lll i=1;i<m;i++)
		{
			lll ll=l+s2*(m-i);
			if(cj>abs(ll-h))
			{
				p2=i;
				cj=abs(ll-h);
			}
		}
		return;
	}
}
int main()
{
	cin>>n;
	lll a[n+5];
	for(lll i=1;i<=n;i++)
		cin>>a[i];
	cin>>m>>p1>>s1>>s2;
	for(lll i=1;i<m;i++) 
		l+=(m-i)*a[i];
	for(lll i=n;i>m;i--)
		h+=(i-m)*a[i];
	if(p1<m)
		l+=(m-p1)*s1;
	if(p1>m) 
		h+=(p1-m)*s1;
	p2=m;
	place();
	cout<<p2;
	return 0;
}

最后,总结坑点:

1,一定要用long long,不然会丢20分!(自己还不知道咋丢的)

2,枚举时一定从小到大枚举!

最后的最后,祝看到这里的老铁们rp++!

祝点赞关注的老铁们(akioi)做的全会,蒙的全对!

感谢各位大佬的耐心观看!

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值