SGU 111 Very simple problem 翻译 题解

111. Very simple problem

每个测试点时间限制: 0.50 sec. 
每个测试点内存限制: 4096 KB

 

给你一个自然数X,输出平方小于或等于X的最大整数。

 

输入

输入包含一个自然数 X (1≤X≤101000).

 

输出

输出答案

 

样例输入

16

 

样例输出

4

================================华丽的分割线 ================================

  第一眼,觉得是个水题,看了数据范围发现暴难!
  我的第一个做法是,网上看到的一个:用X减1,再-3,再-5,再-7,再-2k-1,到小于0,输出K-1。
  最开始觉得不行,后来试了一下,发现:1=1=1^2 
                    1+3=4=2^2
                    1+3+5=9=3^2
                    ...

                    1+...+2*k-1=k^2
  感觉比下面要介绍的方法简单得多,尝试了一下,TLE了。。。。 

  然后就是笔算开根,看了半天才看懂,推荐个地方吧:
  http://www.gaokw.com/gwy/xingce/4183.html,有图有解释,觉得不错。
  再一个,我的代码应该好懂,因为函数都单独抽取出来了,没堆在一起,有面向对象的感觉,呵呵。

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define USE 4
#define INF 10000
#define MAX 500
typedef struct {
	int num[MAX], len;
}bignum;
char str[1000];
bignum a, b, c;

void add(bignum *a, int k)
{
	int i;
	for(i = 1; i <= a->len; i++){
		if(!k){
			break;
		}
		a->num[MAX - i] += k;
		k = a->num[MAX - i] / INF;
		a->num[MAX - i] %= INF;
	}
	if(k){
		a->num[MAX - i] = k;
		a->len++;
	}
}

void dec(bignum *a, bignum *b)
{
	int i, j = 0;
	int len = b->len;
	for(i = 1; i <= len; i++){
		a->num[MAX - i] = a->num[MAX - i] - b->num[MAX - i] - j;
		j = 0;
		while(a->num[MAX - i] < 0){
			a->num[MAX - i] += INF;
			j++;
		}
	}
	if(j){
		a->num[MAX - i] -= j;
	}
	for(i = a->len; i >= 1; i--){
		if(a->num[MAX - i]){
			break;
		}
	}
	a->len = i;
}

void mul(bignum *a, int k)
{
	int i, j = 0;
	//考虑一个特殊情况, k=0时
	if(k == 0){
		memset(a, 0, sizeof(bignum));
		return;
	}
	for(i = 1; i <= a->len; i++){
		a->num[MAX - i] = a->num[MAX - i] * k + j;
		j = a->num[MAX - i] / INF;
		a->num[MAX - i] %= INF;
	}
	if(j){
		a->num[MAX - i] = j;
		a->len++;
	}
}

void output(bignum *a)
{
	int i;
	printf("%d", a->num[MAX - a->len]);
	for(i = a->len - 1; i >= 1; i--){
		printf("%.*d", USE, a->num[MAX - i]);
	}
	printf("\n");
}

int com(bignum *a, bignum *b)
{
	int i;
	if(a->len != b->len){
		return a->len - b->len;
	}
	for(i = a->len; i >= 1; i--){
		if(a->num[MAX - i] != b->num[MAX - i]){
			return a->num[MAX - i] - b->num[MAX - i];
		}
	}
	return 0;
}

int getnum(int len)
{
	static int start = 0;
	int i, n = 0;
	for(i = 0; i < len; i++){
		n *= 10;
		n += str[start + i] - '0';
	}
	start += len;
	return n;
}

int check(int k)
{
	memcpy(&c, &b, sizeof(b));
	//c = (20 * b + k) * k;
	mul(&c, k * 20);
	add(&c, k * k);
	if(com(&a, &c) >= 0){
		return 1;
	}
	return 0;
}

int main(int argc, char **argv)
{
	int i, j, t, n;
	scanf("%s", str);
	n = strlen(str);
	if(n & 1){
		j = getnum(1);
	}else{
		j = getnum(2);
	}
	n = (n + 1) / 2;

	t = sqrt(j);
	add(&a, j - t * t);
	add(&b, t);

	for(i = 2; i <= n; i++){
		mul(&a, 100);
		add(&a, getnum(2));
		for(j = 9; j >= 0; j--){
			if(check(j)){
				break;
			}
		}
		dec(&a, &c);
		mul(&b, 10);
		add(&b, j);
	}
	output(&b);
	return 0;
}

转载于:https://www.cnblogs.com/yylogo/archive/2011/06/12/SGU-111.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值