[数位统计] spoj 1433 The sum

题意:对于数加一位减一位,给定N,求1~N的和。

例子12=1-2+3-4......-1+2=5

思路:

个人思路可能比较复杂,但是思路还是比较清晰的。

首先我们把一个数N分成两个部分,比如4568=1~999+1000~4568,567=1~99+100~567

也就是整百整千的数我们可以递推算出来,虽然找规律也是可以的~

就是1~999=1~99+100~999.

这样算的话 其实就解决了最后计算的问题,更能统一函数。

然后其实我们可以发现,位数是奇数的数,除了个位前面的数是两两抵消的。

比如 100~105=

-1+0-0

+1-0+1

-1+0-2

+1-0+3

....

而且个位便是0~9的和

所以只要算个数的奇偶性以及对10的整除关系就行了。

然后对于偶数为的数

比如1000~9876

我先计算1000~8999 然后 9000~9876

1000~8999其实就是算头尾两数和的差,中间都是抵消的。

然后9000~9876就按位计算就好了 减去和加上和依次类推。

规律拿笔算一下 不能发现的。

然后这道题注意两个地方。。

1、我不理解为什么极限的3个数爆64位了。我特殊处理了。

2、就是特殊处理的时候整数不能那么长,在后面加上LL就好了

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"stack"
#include"algorithm"
#include"iostream"
using namespace std;
long long xx=999999999999998LL;
long long a[2][10],ans[16],ten[16];
long long solve(long long x)
{
    long long len,t=1,n,tep,ans=0;
    len=(long long)log10(x*1.0)+1;
    n=len-1;
    while(n--) t*=10;
    if(len%2)   //奇数位数
    {
        tep=x-t+1;
        ans+=tep/10*a[1][9];
        if(tep%10) ans+=a[1][tep%10-1];
        if(tep%2)
        {
            x/=10;
            t/=10;
            int f=0;
            while(x)
            {
                if(f%2==0) ans-=x/t;
                else ans+=x/t;
                x%=t;
                t/=10;
                f++;
            }
        }
    }
    else   //偶数位数
    {
        ans=ans-t*a[0][x/t-1];
        ans+=(x/t-1)*(t/10)*a[0][9];  //1000~8999
        ans-=(x/t)*(x%t+1);
        tep=0;
        int f=0;
        x%=t;
        t/=10;
        while(x)
        {
            if(f)
            {
                ans-=tep*t*a[0][9];
                ans-=t*a[0][x/t-1];
                ans-=(x/t)*(x%t+1);
            }
            else
            {
                ans+=tep*t*a[0][9];
                ans+=t*a[0][x/t-1];
                ans+=(x/t)*(x%t+1);
            }
            tep=tep*10+x/t;
            x%=t;
            t/=10;
            f^=1;
        }
    }
    return ans;
}
int main()
{
    memset(a,0,sizeof(a));
    int i;
    for(i=1; i<=9; i++) a[0][i]=a[0][i-1]+i;
    for(i=1; i<=9; i++)
    {
        if(i%2) a[1][i]=a[1][i-1]+i;
        else a[1][i]=a[1][i-1]-i;
    }
    long long t=9;
    ans[1]=a[1][9];
    for(i=2; i<=15; i++)
    {
        long long sum=0;
        t=t*10+9;
        sum=solve(t);
        ans[i]=ans[i-1]+sum;
    }

    long long n;
    while(scanf("%lld",&n),n)
    {
        long long len;

        if(n>=xx)
        {
            if(n==xx) puts("409090909090901");
            else if(n==xx+1)  puts("409090909090910");
            else if(n==xx+2) puts("409090909090909");
            continue;
        }
        if(n<10)
        {
            printf("%lld\n",a[1][n]);
            continue;
        }
        len=(long long)log10(n*1.0)+1;
        printf("%lld\n",ans[len-1]+solve(n));
    }
    return 0;
}
时间: 2024-10-16 21:43:01

[数位统计] spoj 1433 The sum的相关文章

[ACM] ural 1057 Amount of degrees (数位统计)

1057. Amount of Degrees Time limit: 1.0 second Memory limit: 64 MB Create a code to determine the amount of integers, lying in the set [X;Y] and being a sum of exactlyK different integer degrees of B. Example. Let X=15, Y=20, K=2, B=2. By this exampl

SQL编程实例:Access数据库,两张表的统计,count、sum聚合函数的使用,iif的使用,group by的使用

小媛在努力 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 在多媒体数据处理中,数据压缩算法尤为重要.小媛上完课后就想自己发明一个数据压缩算法.她想呀想,终于想到一个方法.在多媒体数据中有很多数据都是重复的,所以她想把连续相同的数据用数据出现的次数和数据本身表示.例如:1 1 1 2 3 3 3 3 3  压缩后及为3 1 1 2 5 3(表示3个1,1个2和5个3).有想法后小媛就希望把它用代码实现了.但是大家都知道小媛现在整天都忙着苦B的复习考研,连电脑都摸不到

LeetCode 437. Path Sum III(统计路径和等于sum的路径数量)

题意:统计路径和等于sum的路径数量. (1)节点值可正可负 (2)路径两端不一定是根结点或叶子结点 (3)路径一定是向下 分析:路径起点 (1)位于root(统计以root开头的和等于sum的路径数量) (2)位于root->left子树(递归) (3)位于root->right子树(递归) /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode

URAL 1057 Amount of Degrees(数位统计)

题意:  求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K 个互不相等的B的整 数次幂之和. 思路:对于二进制来说(图片摘自刘聪的浅谈数位类统计问题论文) 现在推广到b进制 因为对于b进制的每一位,我们只需要讨论这一位是否是一,所以我们可以把这个数转换为一个等价的二进制数, 方法是将这个数从左到右第一位不是零或一的位变为1,并把其右边的所有位置一,求出这个二进制数. #include<cstdio> #include<cstring> #include<cm

SPOJ BALLSUM - Ball sum

题目链接:http://www.spoj.com/problems/BALLSUM/ 题目大意:问从N个数中选两个数和小于等于K的概率值,用分数表示. 解题思路:假设要选择小于等于5的数字,那么可选项有(1,4) (1,3) (1,2) (2,3),可以发现实际上是k-2 + k-4 +...当该项为0时停止即可.N个数里面选择两个可以直接n(n-1)/2,表示成分数则可以同除以GCD. 代码: 1 const int maxn = 1e6 + 5; 2 ll n, k; 3 4 ll gcd(

[数位dp] spoj 10738 Ra-One Numbers

题意:给定x.y,为[x,y]之间有多少个数的偶数位和减去奇数位和等于一. 个位是第一位. 例子: 10=1-0=1 所以10是这样的数 思路:数位dp[i][sum][ok] i位和为sum 是否含有前导0. 然后就是因为有负数 所以根据范围把0设置为100 然后最后和等于101则为所求的数. 代码: [cpp] view plaincopyprint? #include"cstdlib" #include"cstdio" #include"cstrin

UVa1640 - The Counting Problem(数位统计)

题意: 统计两个整数a,b之间各个数字(0~9)出现的次数,如1024和1032,他们之间的数字有1024 1025 1026 1027 1028 1029 1030 1031 1032 总共有10个0,10个1,3个3等等. 分析: 因为前导0的干扰,为了计算方便暂时都先计算在内,之后再减; 如果是0~199,那么百位上的0和1各出现一次,s剩下的就是两个00~99,总共两百个二位数,而每个数出现的次数都一样,都是2*(99-00+1)/10; 那么任意的数都可以分解成类似的数字,如3426,

UVA 1640(数位统计)

The Counting Problem Time Limit:3000MS   Memory Limit:Unknown   64bit IO Format:%lld & %llu SubmitStatus Description Given two integers a and b, we write the numbers between a and b, inclusive, in a list. Your task is to calculate the number of occur

[数位dp] spoj 10606 Balanced Numbers

题意: 对于一个数的每个位上的数. 对于每个奇数,如果出现必须出现偶数次. 对于每个偶数,如果出现必须出现奇数次. 思路: 用三进制存储每个数出现的状态,0没出现,1出现奇数次,2出现偶数次. 然后其他和普通数位dp就一样了. 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #i