hhuoj: 1012 欧洲杯

题目描述

两年一度的欧洲杯又开始了,小海可是一个铁杆球迷,每天晚上都会到XX酒吧观看激烈的比赛,而且小海有给小费的习惯,但是他给小费是由原则的:

  1.   总费用必须是5的倍数;
    
  2.   小费必须占总费用的5%~10%之间(包括边界)
    

假设小海在酒吧的消费是A元,小海带了B元来酒吧,小海想知道他有多少种支付方案供选择。

总费用 = 消费 + 小费

输入

多组测试数据,请处理到文件结束。

对于每组测试数据:

包含两个整数A和B。

数据组数<=1000,1<=A,B<=23^1-1,A<=B。

输出

输出一个整数,代表方案数。

样例输入

4 100
23 100

样例输出

0
1

思路:

首先考虑数据较大,并且组数多,不可能使用枚举,必须考虑数学方法。
通过简单代数计算求出,x*20/19<=总消费<=x**10/9(x为消费),求出左右边界。
将边界移至以1为起点,即可把问题转化为从1到n有多少个五的倍数。
还应考虑到对原区间和变换后区间,中间包含到的5的个数会有所不同,只需模拟一下,将变换后区间变为原区间(个位相同),枚举其中包含的5的倍数。
并且考虑左边界是否为五的倍数。不需要考虑右边界,因为上面的枚举过程一定会包含右边界为五的倍数的情况。

我的弱鸡代码:

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

typedef long long ll;
int main(){
	ll a,b;
	while(~scanf("%lld %lld",&a,&b)){
		ll k=0;
		double c=(double)a*20/19,d=(double)a*10/9;
		ll y1=c,y2=d;
		if(y1>b){
			printf("0\n");
			continue;
		}
		if(y2>b)
			y2=b;
		if(c-y1!=0&&(y1+1)<=y2)
			y1++;
		k=y2-y1+1;
		if(y1%10!=0){
		    for(int i=1;i<y1%10;i++){
			    if((k+i)%5==0)
				    k+=5;
				if((1+i)%5==0)
					k-=5;
			}
		}
		else{
			for(int i=1;i<=9;i++){
			    if((k+i)%5==0)
				    k+=5;
				if((1+i)%5==0)
					k-=5;
			}
		}
		if(y1%5==0)
			k+=5;
		k/=5;
		printf("%lld\n",k);
	}
	return 0;
}

克神的神仙代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

int main(){
	ll A,B,l,r;
	while(~scanf("%lld %lld",&A,&B)){
		l=A%19==0?A/19:ceil(A/19.0);
		r=min(A/9,B-A);
		while(r>=1&&(A+l)%5)l++;
		if(r<l)puts("0");
		else printf("%lld\n",(r-l)/5+1);
	}
	return 0;
}

总结:

这道题想了很久,改了很多很多遍才做对,只能说自己太菜……尤其是看了克神的代码后真的无地自容。
但是还是收获了新知识新方法,nice。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值