ACM_51nod 1984(分块、异或性质)

异或约数和

题目传送门[51nod1984]

题意:
定义 f(i) 为 i 的所有约数的异或和,给定 n(1≤n≤1014) ,求 f(1) xor f(2) xor f(3) xor...xor f(n) (其中xor表示按位异或)

样例解释:

f(1) = 1
f(2) = 1 xor 2 = 3
f(3) = 1 xor 3 = 2
f(4) = 1 xor 2 xor 4 = 7
1 xor 3 xor 2 xor 7 = 7

思路:

首先看到这种与异或累和有关的想起的应该是

0^0=0
1^0=1
1^1=0
A^0=A
A^A=0

若记某个数为N,其约数集为{ n1 , n2 , n3……}
则只需要,对在全体约数集中出现次数为奇数的约数进行 ==ans^=ni== , 最终的结果就是答案 ;
然后就可以得到……

明显地,这种方法时间复杂度为 O(n)
我们就可以考虑做一个分块,怎么分呢 ;
定义左界Lef为约数n , 右界Rig为与n在全体集中出现次数相同的最大约数 。
就可以得到这么一个整除分块 ,我们==只需要对出现次数为奇数的段进行约数和,每次都ans^=段和== ,便可以得到答案;
那么问题又来了 ,
如何得到段和呢 。
如果定义G(x)为1~x的异或和,H(l,r)为l ~ r 的异或和
即在正整数上有==H(l , r )=G( r )^G( l - 1 )== ;
而至于求G(x)则有O(1)的算法:

f(1, n)  =  
 f(0, n)  =
n  		n % 4 == 0
1  		n % 4 == 1
n +1   	n % 4 == 2
0     	n % 4 == 3
inline int Sigxor( int n )
{	
	return ((n%4)&1) ? ((n%4)>>1)^1 : ((n%4)>>1)^n ;	
	}

到这里我们的问题就全都解决啦 o ' u ' o !

#include <bits/stdc++.h>
#define N 100050
#define lodou long double
#define lll __int128
#define INmF 0x3f3f3f3f
#define lbt(x) (x&(-x))
#define mes(a,b) memset(a,b,sizeof(a))
#define qwq(a,b) for(int i=a ;i<=b;++i)
#define qeq(a,b) for(int j=a ;j<=b;++j)
#define qaq(a,b,c) for(ll i=a ; i<=b ;i=c+1)
#define IOS ios::sync_with_stdio(false)
#define  UPCASE( c ) ( ((c) >= 'c' && (c) <= 'z') ? ((c) - 0x20) : (c) )
using namespace std;
const double Eps = 1e-8 ;
const double pi  = acos(-1) ;
const long long mod = 1e9+7 ;
typedef long long int ll;
inline ll pow_mod (ll a,ll b) {ll res=1;a%=mod; if(b<0) return -1; for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
inline ll fas_mul (ll a,ll b) { return ( (a*b-(ll)(((long double)a*b+0.5)/mod)*mod)%mod+mod)%mod ; }

namespace io {

    #define in(a) a=read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('\n')

    #define I_int __int128
    inline I_int read() {
        I_int x = 0 , f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
        while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
        return x * f ;
    }
    char F[ 200 ] ;
    inline void write( I_int x ) {
        if( x == 0 ) { putchar( '0' ) ; return ; }
        I_int tmp = x > 0 ? x : -x ;
        if( x < 0 ) putchar( '-' ) ;
        int cnt = 0 ;
        while( tmp > 0 ) {
            F[ cnt ++ ] = tmp % 10 + '0' ;
            tmp /= 10 ;
        }
        while( cnt > 0 ) putchar ( F[ -- cnt ] ) ;
    }
    #undef I_int

}using namespace io ;
//ouououououououououououououououououououououououououououououououououououououououououououououououou

inline ll Sigxor( ll n )
{	return ((n%4)&1) ? ((n%4)>>1)^1 : ((n%4)>>1)^n ;	}

ll Blocking( ll n )
{
	ll 	res=0 ,
		tem=0 ;
	qaq( 1 , n , tem ){
		tem=n/(n/i) ;//分块
		if( (n/i)&1 )
			res^=Sigxor(i-1)^Sigxor(tem);//i~tem段的异或和
	}
	return res ;
}
unsigned main()
{
    ll n=read();
  	outn(Blocking(n));
}

学艺不精告辞

发布了7049 篇原创文章 · 获赞 470 · 访问量 66万+

猜你喜欢

转载自blog.csdn.net/cpongo3/article/details/98479718