CodeForces 373B Making Sequences is Fun

这应该是一个水题吧,,看学长们写的都好轻松的样子,不过我自己写的时候遇到了一个小问题,因为数据范围很大在运算的时候很有可能出现数据溢出的现象。

写的时候所有变量都采用的long long 型,尽量防止了数据范围不够。


题目大意:

给定一个整数w代表总价值上限

S(x)表示整数x的位数,一个整数x的价值是S(x)*k,k是给定的一个单位价值(整数每有一位价值就加上k)

m是整个整数列的起始项,求总价值不超过w的以m开头的连续递增整数列的最大长度


大致思路:

对于一个整数m,用一个函数digit(m)求它的位数

由于求的是总长度,以 cnt 来统计加入的整数数量,由于m在一定的连续范围内位数不变,也就是说,在m的位数增加之前,这一段整数的价值都是一样的,那么每次处理时处理一段整数。


Result  :  Accepted    Memory : 0 KB   Time : 15 ms

/*
 * Author : Gatevin
 * Time : 2014.4.9 19:28
 * Problem : CodeForces 373B Making Sequences is Fun
 * Tag : math
 */

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lint;
lint w,m,k;

lint pow(lint base, lint y)
{
    lint tmp = 1;
    for(lint i = 1; i <= y; i++)
    {
        tmp *= base;
    }
    return tmp;
}

lint digit(lint x)//x的位数
{
    lint a = 1;
    while(pow(10,a) <= x)
    {
        a++;
    }
    return a;
}

lint remain(lint m)//m到下一进位的整数的数量
{
    lint a = 1;
    while(pow(10,a) <= m)
    {
        a++;
    }
    return pow(10,a) - m;
}

lint decrease(lint w, lint many, lint d, lint k)//这是类似于快速幂的一个想法,有效防止了数据溢出
{
    lint a = 1;
    while(many)
    {
        if(many&1)
        {
            w -= d*k*a;
        }
        many >>= 1;//类似于整数的快速幂,和数字逻辑里的8421码原理有点像
        a *= 2;
    }
    return w;
}

int main()
{
    cin>>w>>m>>k;
    lint cnt = 0;
    while(w >= digit(m)*k)//当价值w足以满足下一个整数
    {
        lint tmp = w/(digit(m)*k);//接下来可以有多少个这样位数的整数
        if(tmp < remain(m))
        {
            w = decrease(w,tmp,digit(m),k);//这里如果改成减去tmp*digit(m)*k会出现数据溢出,,交的时候会在test13上wa掉了
            m += tmp;
            cnt += tmp;
        }
        else
        {
            w = decrease(w,remain(m),digit(m),k);
            cnt += remain(m);
            m = pow(10,digit(m));
        }
    }
    cout<<cnt;
    return 0;
}

PS : 坑爹的马原课,,,,,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值