HDU 4919 Exclusive or 解題報告(規律+大數)

Exclusive or

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 131    Accepted Submission(s): 49


Problem Description
Given n, find the value of


Note: ⊕ denotes bitwise exclusive-or.
 

Input
The input consists of several tests. For each tests:

A single integer n (2≤n<10500).
 

Output
For each tests:

A single integer, the value of the sum.
 

Sample Input
3 4
 

Sample Output
6 4
 

Author
Xiaoxu Guo (ftiasch)
 

Source
 
    解題報告:比賽的時候已經有思路了,最後debug的時間卻不夠,沒能搞定。

    官方的方法是推出公式。我這裏直接找規律來做的。列出(0, n), (1, n-1), (2, n-2), ... 所有相關數的二進制和異或值,yy出規律。這裏用了(0, n),所以最後減去n。

    規律的話就是總結一下每一位的1隔多少次出現多少次,細心觀察可以發現的,不多說了。我的大數模板裏沒除法,轉二進制時二分來做的。代碼如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <iomanip>
using namespace std;
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
//    freopen("input.in", "r", stdin);
//    freopen("output.out", "w", stdout);
#endif // ACM
    work();
}

/***************************************************/

const int K = 10000;    // 數組裏每位代表1W
const int M = 500;      // 一共500位
const char show[] = "%04d";
LL mulTmp[M];           // 乘法臨時數組
struct Bignum
{
    LL a[M];            // 大數數組
    int len;            // 長度
    bool negative;      // 正負

    Bignum()
    {
        clear();
    }

    void clear()
    {
        len=0;
        negative=false;
        memset(a, 0, sizeof(a));
    }

    Bignum(LL num)
    {
        *this=num;
    }

    Bignum(char * str)
    {
        *this=str;
    }

    Bignum operator=(LL num)
    {
        clear();
        if(num<0) negative=true, num=-num;
        while(num)
            a[len++]=num%K,num/=K;
        return *this;
    }

    Bignum operator=(char * str)
    {
        clear();
        if(str[0] == '-')
            negative = true, str++;

        int l = strlen(str);

        int width = (int)log10(K + 0.5);
        int idx = 0;
        dff(i, l-1, 0)
        {
            if(idx == width) idx=0, len++;
            a[len] = a[len] + (str[i]-'0')*pow(10.0, idx);
            idx++;
        }

        len++;
        return *this;
    }

    Bignum(const Bignum& cmp)
    {
        memcpy(this, &cmp, sizeof(Bignum));
    }

    Bignum operator=(const Bignum& cmp)
    {
        memcpy(this, &cmp, sizeof(Bignum));
        return *this;
    }

    int absCmp(const Bignum& cmp) const
    {
        if(len!=cmp.len)
            return len>cmp.len?1:-1;

        for(int i=len-1;i>=0;i--)
            if(a[i]!=cmp.a[i])
                return a[i]>cmp.a[i]?1:-1;

        return 0;
    }

    int absCmp(LL num) const
    {
        Bignum cmp(num);
        return absCmp(cmp);
    }

    bool operator<(const Bignum& cmp) const
    {
        if(negative^cmp.negative)
            return negative?true:false;

        if(negative)
            return absCmp(cmp)>0;
        else
            return absCmp(cmp)<0;
    }

    bool operator<(LL num) const
    {
        Bignum cmp(num);
        return *this<cmp;
    }

    bool operator==(const Bignum& cmp)
    {
        if(negative^cmp.negative)
            return false;
        return absCmp(cmp)==0;
    }

    bool operator==(LL num)
    {
        Bignum cmp(num);
        return *this==cmp;
    }

    void absAdd(const Bignum& one, const Bignum& two)
    {
        len=max(one.len, two.len);
        for(int i=0;i<len;i++)
        {
            a[i]+=one.a[i]+two.a[i];
            if(a[i]>=K) a[i]-=K, a[i+1]++;
        }
        if(a[len]) len++;
    }

    void absSub(const Bignum& one, const Bignum& two)
    {
        len=one.len;
        for(int i=0;i<len;i++)
        {
            a[i]+=one.a[i]-two.a[i];
            if(a[i]<0) a[i+1]--,a[i]+=K;
        }
        while(len>0 && a[len-1]==0) len--;
    }

    void absMul(const Bignum& one, const Bignum& two)
    {
        len=one.len+two.len;
        memset(mulTmp, 0, sizeof(mulTmp));
        for(int i=0;i<one.len;i++) for(int j=0;j<two.len;j++)
            mulTmp[i+j] += (LL)one.a[i]*two.a[j];
        for(int i=0;i<len;i++)
            mulTmp[i+1]+=mulTmp[i]/K, a[i]=mulTmp[i]%K;
        while(len>0 && a[len-1]==0) len--;
    }

    Bignum operator+(const Bignum& cmp)
    {
        Bignum c;
        if(negative^cmp.negative)
        {
            bool res = absCmp(cmp)>0;
            c.negative = !(negative^res);
            if(res)
                c.absSub(*this, cmp);
            else
                c.absSub(cmp, *this);
        }
        else if(negative)
        {
            c.negative=true;
            c.absAdd(*this, cmp);
        }
        else
        {
            c.absAdd(*this, cmp);
        }
        return c;
    }

    Bignum operator-(const Bignum& cmp)
    {
        Bignum cpy;
        if(cpy==cmp)
            return *this;
        else
            cpy=cmp, cpy.negative^=true;

        return *this+cpy;
    }

    Bignum operator*(const Bignum& cmp)
    {
        Bignum c;
        if(c==cmp || c==*this)
            return c;

        c.negative = negative^cmp.negative;
        c.absMul(*this, cmp);
        return c;
    }

    void output()
    {
        if(len==0)
        {
            puts("0");
            return;
        }

        if(negative)
            printf("-");

        printf("%d", a[len-1]);
        for(int i=len-2;i>=0;i--)
            printf(show, a[i]);
        puts("");
    }
};

int tot;
Bignum two[3333];
void init()
{
    two[tot = 0] = 1;
    while(two[tot].len <= 250)
        two[tot+1] = two[tot] * 2, tot++;
}

char str[3333];
int bb[3333];
Bignum front[3333];

void work()
{
    init();

    while(scanf("%s", str) == 1)
    {
        Bignum now = str;
        Bignum now2 = now;

        // 找到最高位
        int len = upper_bound(two, two+tot, now) - two;
        memset(bb, 0, sizeof(bb));
        // 轉成二進制存儲
        dff(i, len-1, 0) if(!(now < two[i]))
            bb[i] = true, now = now - two[i];

        front[len].clear();
        dff(i, len-1, 0)
        {
            front[i] = front[i+1] * 2;
            if(bb[i])
                front[i] = front[i] + 1;
        }

        Bignum ans;
        Bignum end;

        ff(i, len)
        {
            if(bb[i])
            {
                ans = ans + two[i] * (end * front[i] + front[i] + end);
                end = end + two[i];
            }
            else
            {
                ans = ans + two[i] * front[i] * (two[i] - end - 1);
            }
        }

        (ans - now2).output();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章