洛谷 8 月月赛

洛谷 8 月月赛

第一次打月赛,水了200
ψ(*`ー´)ψ

T1 造房子

题目

p i g s t d pigstd pigstd a a a A A A 材料和 b b b B B B 材料,造第 i i i 层楼需要 i i i A A A 材料与 i i i B B B 材料。
但是 p i g s t d pigstd pigstd 觉得房子不够高,于是他拿出了 c c c 块钱,每块钱都可以用来买 1 个 A A A 材料或者 1 个 B B B 材料。
现在 p i g s t d pigstd pigstd 想知道,他最多能建多少层楼的房子。


输入

第一行三个整数 a a a, b b b


输出

一行一个整数,表示 p i g s t d pigstd pigstd 最多能建多少层楼的房子。


样例

input 1
1 2 3

output 1
2

input 2
1 2 5

output 2
2


说明/提示

【样例 1 说明】
p i g s t d pigstd pigstd 买 2 个 A A A 材料和 1 个 B B B 材料后就有 3 个 A A A 材料和 3 个 B B B 材料,最多可以建 2 层楼的房子。
(花费 1+2 个 A A A 材料和 1+2 个 B B B 材料)

【样例 2 说明】
p i g s t d pigstd pigstd 买 3 个 A A A 材料后就有 4 个 A A A 材料和 5 个 B B B 材料,最多可以建 2 层楼的房子。
(花费 1+2 个 A A A 材料和 1+2 个 B B B 材料)

【数据规模与约定】
对于 100% 的数据,0≤ a a a, b b b, c c c≤10^12。
在这里插入图片描述


解题思路

预处理
先将 A A A材料和 B B B材料的个数差的差距变小
如果 c c c还有剩余,平分给 A A A材料和 B B B材料

二分答案
二分可以建到第几层
用高斯定理求出一共要用的材料
最后输出左边界


代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long a,b,c,n,l,r; 
double x;
int main()
{
	scanf("%lld%lld%lld",&a,&b,&c);
	if (a>b)
	   swap(a,b);  //小的给A材料
	if (a<b)  //等于就不用补差了
       if (c+a>=b)
	   {
	   	  c=c-(b-a);
	   	  a=b;
	   } 
	   else {
	      a+=c; 
	      c=0;
	   }
	a+=c/2,b+=c/2; //c平分给A和B
	l=1,r=2000000;  //定边界
	while (l<r)
	{  
		  long long mid=(l+r+1)/2;
		  x=(mid+1)*(mid*1.0/2);  //高斯定理求材料数
		  if (x>a)  //不够往左靠,有剩往右靠
		     r=mid-1;
		     else l=mid;
	}
    printf("%lld\n",l);
	return 0;
} 

T2 排列

题目

p i g s t d pigstd pigstd 有一堆数,他想在这么多数中选出若干个数排成一列,记为 x x x 1, x x x 2,⋯ , x p xp xp p p p 为数的个数)。
这一列数合法当且仅当满足以下条件:

  • p p p≥2。
  • y i yi yi= x x x i i i+1)− x i xi xi​(特别的, y p yp yp= x x x 1− x p ​ xp​ xp),如果把 y y y 1 到 y p yp yp y y y 1, y y y 2,⋯ , y p yp yp​ 的顺序排成一圈,那么每两个相邻的数互为相反数且绝对值都为 k k k

p i g s t d pigstd pigstd 想知道,在所有合法的数列中,所有在这个数列中的数之和最大是多少。


输入

第一行两个整数 n n n, k k k
接下来 n n n 行,每行两个整数 a i ai ai, b i bi bi​,表示 p i g s t d pigstd pigstd b i bi bi​ 个 a i ai ai​。
不保证 ai​ 互不相同,若有 ai 相同则累加其个数计算。


输出

一行一个整数,表示在每一种排列中,所有在这个排列中的数的最大的和。
若没有合法的排列,则只输出 NO。


样例

input
4 3
1 5
2 4
3 3
0 2

output
6


说明/提示

【样例 1 说明】
p i g s t d pigstd pigstd 的排列为:0,3,0,3 或 3,0,3,0 时,总和最大,为 6。

【数据规模与约定】
对于 100% 的数据,1≤ n n n≤10 ^ 6,0≤ k k k, a i ai ai≤10 ^ 6,1≤ b i bi bi≤10 ^ 6。

本题采用捆绑测试。

  • S u b t a s k Subtask Subtask 1(5 p o i n t s points points):保证无合法的数列;
  • S u b t a s k Subtask Subtask 2(15 p o i n t s points points): k k k=0;
  • S u b t a s k Subtask Subtask 3(5 p o i n t s points points): n n n=1;
  • S u b t a s k Subtask Subtask 4(5 p o i n t s points points): n n n=2;
  • S u b t a s k Subtask Subtask 5(30 p o i n t s points points): n n n, k k k, a i ai ai, b i bi bi≤10^3;
  • S u b t a s k Subtask Subtask 6(40 p o i n t s points points):无特殊限制。

解题思路

我们可以从样例解释中看出
数列一定是 x x x, y y y, x x x, y y y, x x x, y y y x x x, y y y
并且一定是偶数个的(题目中特别解释,第一个数和最后一个数的差也要满足 k k k,除非 k k k=0,否则 x x x!= y y y
我们可以枚举 x x x
y y y= x x x+ k k k,如果 y y y存在,我们就可以构造一个数列

  • k k k == 0时, x x x == y,所以要特判 x x x的个数必须大于2( p p p≥2), x x x* a a a[ x x x]和当前的最优答案比较
  • k k k>0时,取 x x x y y y的个数中的较小值和( x x x+ y y y)相乘与当前最优答案比较

代码
#include<iostream>
#include<cstdio>
using namespace std;
long long n,k,x,y,ma,c,p,a[1000020];
long long ans;
int main()
{
	scanf("%lld%lld",&n,&k);
	for (int i=1;i<=n;i++)
	{
		scanf("%lld%lld",&x,&y);
		ma=max(x,ma);
		a[x]+=y;  //累加个数
	}
	for (int i=0;i<=ma-k;i++)
	    if (a[i]!=0 && a[i+k]!=0)  //保证x和y都有
	    {   
	    	if (k!=0)  //分类讨论
	    	{ 
			    p=1;
	    		c=min(a[i],a[i+k]);  //取个数中的较小值
	    		long long x=(i+i+k)*c;  //求和
	    		ans=max(ans,x);  //更新答案
	    	}
	    	else if (a[i]>1)  //特判个数
			     {
	    		    p=1;
	    		    long long x=i*a[i];  //求和
	    		    ans=max(ans,x);  //更新答案
	    	     }
	    }
    if (p)  //能构造出合法数列
	   printf("%lld\n",ans);
	   else printf("NO");
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值