ACM学习历程—SNNUOJ1132 余数之和(数论)

Description

F(n) = (n % 1) + (n % 2) + (n % 3) + ...... (n % n)。其中%表示Mod,也就是余数。
例如F(6) = 6 % 1 + 6 % 2 + 6 % 3 + 6 % 4 + 6 % 5 + 6 % 6 = 0 + 0 + 0 + 2 + 1 + 0 = 3。
给出n,计算F(n)。

Input

输入1个数N(2 <= N <= 10^12)。

Output

输出F(n)。

Sample Input

6

Sample Output

3

这是51NOD上的一道题,由于提交不了,所以搞到我们学校的OJ提交了。

这个题目n达10^12这么大,自然不可能走一遍。

然后由于n%i = n-[n/i]*i

所以sum(n%i) = sum(n-[n/i]*i) = n*n - sum([n/i]*i)。

考虑到取整那部分,当i在连续的一段区间内可能值会不变。

=>[n/i] = [n/j] => j = n/(n/i)这里的除法为取下整。

于是便可以考虑分组运算了。

由于数据很大,用了C++高精度。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <string>
#define LL long long

using namespace std;

const int UNIT = 10;
struct Bignum
{
    int val[30];
    int len;

    Bignum()
    {
        memset(val, 0, sizeof(val));
        len = 1;
    }

    Bignum operator=(const LL &a)
    {
        LL t, p = a;
        len = 0;
        while (p >= UNIT)
        {
            t = p - (p/UNIT)*UNIT;
            p = p / UNIT;
            val[len++] = t;
        }
        val[len++] = p;
        return *this;
    }

    Bignum operator+(const Bignum &a) const
    {
        Bignum x = a;
        int L;
        L = a.len > len ? a.len : len;
        for (int i = 0; i < L; ++i)
        {
            x.val[i] += val[i];
            if (x.val[i] >= UNIT)
            {
                x.val[i+1]++;
                x.val[i] -= UNIT;
            }
        }
        if (x.val[L] != 0)
            x.len = L+1;
        else
            x.len = L;
        return x;
    }

    Bignum operator-(const Bignum &a) const
    {
        bool flag;
        Bignum x1, x2;
        if (*this > a)
        {
            x1 = *this;
            x2 = a;
            flag = 0;
        }
        else
        {
            x1 = a;
            x2 = *this;
            flag = 1;
        }
        int j, L = x1.len;
        for (int i = 0; i < L; ++i)
        {
            if (x1.val[i] < x2.val[i])
            {
                j = i+1;
                while (x1.val[j] == 0)
                    j++;
                x1.val[j--]--;
                while (j > i)
                    x1.val[j--] += UNIT-1;
                x1.val[i] += UNIT-x2.val[i];
            }
            else
                x1.val[i] -= x2.val[i];
        }
        while (x1.val[x1.len-1] == 0 && x1.len > 1)
            x1.len--;
        if (flag)
            x1.val[x1.len-1] = -x1.val[x1.len-1];
        return x1;
    }

    Bignum operator*(const Bignum &a) const
    {
        Bignum x;
        int i, j, up;
        int x1, x2;
        for (i = 0; i < len; i++)
        {
            up = 0;
            for (j = 0; j < a.len; j++)
            {
                x1 = val[i]*a.val[j] + x.val[i+j] + up;
                if (x1 >= UNIT)
                {
                    x2 = x1 - x1/UNIT*UNIT;
                    up = x1 / UNIT;
                    x.val[i+j] = x2;
                }
                else
                {
                    up = 0;
                    x.val[i+j] = x1;
                }
            }
            if (up != 0)
                x.val[i+j] = up;
        }
        x.len = i + j;
        while (x.val[x.len-1] == 0 && x.len > 1)
            x.len--;
        return x;
    }

    Bignum operator/(const int &a) const
    {
        Bignum x;
        int down = 0;
        for (int i = len-1; i >= 0; --i)
        {
            x.val[i] = (val[i]+down*UNIT) / a;
            down = val[i] + down*UNIT - x.val[i]*a;
        }
        x.len = len;
        while (x.val[x.len-1] == 0 && x.len > 1)
            x.len--;
        return x;
    }

    LL operator%(const LL &a) const
    {
        LL x = 0;
        for (int i = len-1; i >= 0; --i)
            x = ((x*UNIT)%a+val[i]) % a;
        return x;
    }

    bool operator>(const Bignum &a) const
    {
        int now;
        if (len > a.len)
            return true;
        else if (len == a.len)
        {
            now = len - 1;
            while (val[now] == a.val[now] && now >= 0)
                now--;
            if(now >= 0 && val[now] > a.val[now])
                return true;
            else
                return false;
        }
        else
            return false;
    }
}ans, tmp, ttmp;

LL n;

void work()
{
    ans = n;
    ans = ans*ans;
    LL j;
    for (LL i = 1; i <= n; i++)
    {
        j = n/(n/i);
        tmp = i+j;
        ttmp = j-i+1;
        tmp = tmp*ttmp;
        tmp = tmp/2;
        ttmp = n/i;
        tmp = tmp*ttmp;
        ans = ans-tmp;
        i = j;
    }
}

void output()
{
    for (int i = ans.len-1; i >= 0; --i)
        printf("%d", ans.val[i]);
    printf("\n");
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%lld", &n) != EOF)
    {
        work();
        output();
    }
    return 0;
}

时间: 2024-10-11 16:25:07

ACM学习历程—SNNUOJ1132 余数之和(数论)的相关文章

ACM学习历程—HDU5585 Numbers(数论 || 大数)(BestCoder Round #64 (div.2) 1001)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5585 题目大意就是求大数是否能被2,3,5整除. 我直接上了Java大数,不过可以对末尾来判断2和5,对所有位的和来判断3. 代码就不粘了.

ACM学习历程—HDU5668 Circle(数论)

http://acm.hdu.edu.cn/showproblem.php?pid=5668 这题的话,假设每次报x个,那么可以模拟一遍, 假设第i个出局的是a[i],那么从第i-1个出局的人后,重新报数到他假设经过了p个人, 那么自然x = k(n-i)+p(0<= i < n) 即x = p (mod n-i) 然后显然可以得到n个这样的方程,于是就是中国剩余定理了. 代码: #include <iostream> #include <cstdio> #includ

ACM学习历程—HDU5637 Transform(数论 &amp;&amp; 最短路)

题目链接:http://codeforces.com/problemset/problem/590/A 题目大意是给两种操作,然后给你一个s,一个t,求s至少需要多少次操作到t. 考虑到第一种操作是将某一位取反,而第二种操作是抑或一个数. 显然第一种操作也是可以通过抑或一个数得到的.比如:第i位取反,相当于抑或(1<<i)这个数.于是就将n个数扩大到n+17就可以了,因为100000最多17位. 此外如果p^a^b^c...=q的话,那么a^b^c...=p^q.于是,只需要求出p^q至少需要

ACM学习历程—HDU1719 Friend(数论)

Description Friend number are defined recursively as follows. (1) numbers 1 and 2 are friend number; (2) if a and b are friend numbers, so is ab+a+b; (3) only the numbers defined in (1) and (2) are friend number. Now your task is to judge whether an

ACM学习历程—HDU 4726 Kia&#39;s Calculation( 贪心&amp;&amp;计数排序)

DescriptionDoctor Ghee is teaching Kia how to calculate the sum of two integers. But Kia is so careless and alway forget to carry a number when the sum of two digits exceeds 9. For example, when she calculates 4567+5789, she will get 9246, and for 12

ACM学习历程—HDU 5023 A Corrupt Mayor&#39;s Performance Art(广州赛区网赛)(线段树)

Problem Description Corrupt governors always find ways to get dirty money. Paint something, then sell the worthless painting at a high price to someone who wants to bribe him/her on an auction, this seemed a safe way for mayor X to make money. Becaus

ACM学习历程—UESTC 1226 Huatuo&#39;s Medicine(数学)(2015CCPC L)

题目链接:http://acm.uestc.edu.cn/#/problem/show/1226 题目就是构造一个对称的串,除了中间的那个只有1个,其余的两边都是对称的两个,自然答案就是2*n-1. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #

ACM学习历程—广东工业大学2016校赛决赛-网络赛F 我是好人4(数论)

题目链接:http://gdutcode.sinaapp.com/problem.php?cid=1031&pid=5 这个题目一看就是一道数论题,应该考虑使用容斥原理,这里对lcm进行容斥. 不过直接上去是T,考虑到序列中同时存在i和ki的话,其实只需要考虑i,所以先对序列中为倍数的对进行处理. 这里的容斥用了hqw的写法. 代码: #include <iostream> #include <cstdio> #include <cstdlib> #includ

ACM学习历程—HDU 3092 Least common multiple(数论 &amp;&amp; 动态规划 &amp;&amp; 大数)

hihoCoder挑战赛12 Description Partychen like to do mathematical problems. One day, when he was doing on a least common multiple(LCM) problem, he suddenly thought of a very interesting question: if given a number of S, and we divided S into some numbers