[51nod1310]Chandrima and XOR
有这样一个小到大排列的无穷序列S:1, 2, 4, 5, 8......,其中任何一个数转为2进制不包括2个连续的1。给出一个长度为N的正整数数组A,A1, A2......An记录的是下标(下标从1开始)。求S[A1] Xor S[A2] Xor S[A3] ..... Xor S[An]的结果(Xor 为异或运算),由于该数很大,输出Mod 1000000007的结果。
例如:A = {1, 2, 3},对应S[1] = 1, S[2] = 2, S[3] = 4。1 Xor 2 Xor 4 = 7。
Input
第1行:1个数N,表示数组A的长度(1 <= N <= 50000)。
第2 - N + 1行:每行一个数,对应数组A的元素A[i](1 <= A[i] <= 10^18)。
Output
输出一个数,S[A1] Xor S[A2] Xor S[A3] ..... Xor S[An]的结果Mod 1000000007。
完全不会搞只能膜题解系列。
实际上这道题可以通过O((logn)^2)的时间推出任意一项。
我们以每一个2的整数次方作为分割点,把这个数列分割成很多块。设F(n)为2^n到2^(n+1)之间的所有满足要求的数字(不包括2^(n+1))。因为二进制中不能有连续的0,所以F(n)=sigma{F(k)|0<=k<=n-2}+1,又知F(n-1)=sigma{F(k)|0<=k<=n-3}+1,可得F(n)=F(n-2)+F(n-1)-1+1=F(n-1)+F(n-2),因此结论:
有1个数在[1,2),1个数在[2,4),2个数在[4,8),3个数在[8,16)…………
而每次可以用二分查找来确定a的位置在2^m和2^(m+1)之间,a减去[1,2^m]之间所有数的个数,重新递归查找。。。(注意减去的是闭区间!)递归深度不会超过logn,因为它是按斐波那契数列的和递减的。每一次递归的m位置异或1,最后会得到一个01数组,按照进制转换然后求模就行了。。
一共有n个数,对于每一次查找的复杂度是O((logn)^2),总复杂度不会达到O(n(logn)^2)。
讲道理那个查找是一个log的....
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 #include<cstdlib> 8 #include<bitset> 9 //#include<ctime> 10 #define ll long long 11 #define ull unsigned long long 12 #define ui unsigned int 13 #define d double 14 //#define ld long double 15 using namespace std; 16 const int maxn=233,modd=1000000007; 17 ll pre[maxn],f[maxn],two[maxn]; 18 int i,j,k,n,m,MX; 19 bool u[90]; 20 21 int ra,fh;char rx; 22 inline int read(){ 23 rx=getchar(),ra=0,fh=1; 24 while((rx<'0'||rx>'9')&&rx!='-')rx=getchar(); 25 if(rx=='-')fh=-1,rx=getchar(); 26 while(rx>='0'&&rx<='9')ra=ra*10+rx-48,rx=getchar();return ra*fh; 27 } 28 29 inline int get(ll x){ 30 int i; 31 for(i=MX;i>0&&x>1;i--)if(x<=pre[i]&&x>pre[i-1])x-=pre[i-1]+1,u[i]^=1,i--;//,printf(" %d\n",i); 32 u[0]^=x>0; 33 } 34 int main(){ 35 f[0]=f[1]=1,two[0]=pre[0]=1,two[1]=pre[1]=2; 36 for(i=2;i<=233;i++){ 37 f[i]=f[i-2]+f[i-1],two[i]=(two[i-1]<<1)%modd, 38 pre[i]=pre[i-1]+f[i]; 39 if(pre[i]>1e18)break; 40 }MX=i; 41 42 n=read();ll a;int ans=0; 43 // for(i=1;i<=233;i++)printf(" %d\n",get(i,MX)); 44 for(i=1;i<=n;i++)scanf("%lld",&a),get(a); 45 for(i=0;i<=MX;i++)if(u[i])(ans+=two[i])%=modd; 46 printf("%d\n",ans); 47 }