知识点补档2

Fib数列性质

f ( n ) = 5 5 ( ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ) f(n)=\frac{\sqrt 5}{5}((\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n) f(n)=55 ((21+5 )n(215 )n)

∑ i = 1 n f ( i ) = f ( n + 2 ) − 1 \sum_{i=1}^n f(i)=f(n+2)-1 i=1nf(i)=f(n+2)1

∑ i = 1 n f ( i ) 2 = f ( n ) ∗ f ( n + 1 ) \sum_{i=1}^n f(i)^2=f(n)*f(n+1) i=1nf(i)2=f(n)f(n+1)

∑ i = 1 n i f ( i ) = n ∗ f ( n + 2 ) − f ( n + 3 ) + 2 \sum_{i=1}^n if(i)=n*f(n+2)-f(n+3)+2 i=1nif(i)=nf(n+2)f(n+3)+2

∑ i = 1 n f ( 2 i − 1 ) = f ( 2 n ) − f ( 2 ) + f ( 1 ) \sum_{i=1}^n f(2i-1)=f(2n)-f(2)+f(1) i=1nf(2i1)=f(2n)f(2)+f(1)

∑ i = 1 n f ( 2 i ) = f ( 2 n + 1 ) − f ( 1 ) \sum_{i=1}^n f(2i)=f(2n+1)-f(1) i=1nf(2i)=f(2n+1)f(1)

g c d ( f [ i ] , f [ i + 1 ] ) = 1 gcd(f[i],f[i+1])=1 gcd(f[i],f[i+1])=1

f [ m + n ] = f [ m − 1 ] f [ n ] + f [ m ] f [ n + 1 ] f[m+n]=f[m-1]f[n]+f[m]f[n+1] f[m+n]=f[m1]f[n]+f[m]f[n+1]

g c d ( f [ n + m ] , f [ n ] ) = g c d ( f [ n ] , f [ m ] ) gcd(f[n+m],f[n])=gcd(f[n],f[m]) gcd(f[n+m],f[n])=gcd(f[n],f[m])

g c d ( f [ n ] , f [ n + m ] ) = f [ g c d ( n , n + m ) ] gcd(f[n],f[n+m])=f[gcd(n,n+m)] gcd(f[n],f[n+m])=f[gcd(n,n+m)]

线性基

线性基是构造出一组序列 p 1 , p 2 , … , p n p_1,p_2, \ldots , p_n p1,p2,,pn,使得从这些数字中任选一个子集的异或和的值域同等于从原序列中任选一个子集的异或和的值域。同时保证 p i p_i pi在二进制下的最高位是 2 i 2^i 2i。这样求异或和最大的时候就可以按位来贪心。

构造方法:对于一个需要插入线性基的数 x x x,首先找到它在二进制位下的最高位 i i i,检查 p i p_i pi是否已经生成。若尚未生成,则令 p i = x p_i=x pi=x并结束操作,否则令 x = x    x o r    p i x = x \; xor \; p_i x=xxorpi,并继续插入操作。

//给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

struct Node{
    ll p[70];
    void insert(ll x) {
        for (int j = 63; j >= 0; --j) {
            if (!(x>>j)) continue;
            if (!p[j]) {p[j]=x;return;}
            x^=p[j];
        }
    }
    ll query(ll x) {
        for (int j = 63; j >= 0; --j)
            x = max(x, x^p[j]);
        return x;
    }
}S;

int main()
{
    int n;
    ll x;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &x);
        S.insert(x);
    }
    cout << S.query(0) << '\n';
    return 0;
} 

其中 q u e r y ( x ) query(x) query(x)是查询异或上 x x x后的最大值,如果要直接查最大值的话直接 q u e r y ( 0 ) query(0) query(0)就好了。

两个线性基可以暴力合并,把其中一个直接插入到另一个中即可,复杂度为 O ( log ⁡ 2 n ) O(\log^2n) O(log2n)

线性基还可以查询第 k k k小,需要重构一下原有的线性基,保证:线性基中某一个元素的非最高位为1当且仅当这个位置对应的线性基元素不存在。

//多组样例,给定n个数,询问这n个数第k小的异或值
#include <bit/stdc++.h>
using namespace std;
#define ll long long

struct xxj{
    ll p[65],q[65];int fg,cnt;
    void init() {
        memset(p, 0, sizeof(p));
        fg = cnt = 0;
    }
    void insert(ll x) {
        for (int i = 62; ~i; --i) {
            if (!(x>>i)) continue;
            if (!p[i]) {
                p[i] = x;
                return;
            }
            x ^= p[i];
        }
        fg = 1;
    }
    void rebuild() {
        for (int i = 62; ~i; --i)
            for (int j = i-1; ~j; --j)
                if ( p[i] &(1ll << j) ) p[i] ^= p[j];
        for (int i = 0; i <= 62; ++i) 
            if (p[i]) q[cnt++] = p[i];
    }
    ll query(ll k) {
        if (fg) --k;
        if (k >= (1ll << cnt)) return -1;
        ll res = 0;
        for (int i = cnt-1; ~i; --i)
            if (k & (1ll << i)) res ^= q[i];
        return res;
    }
}S;

int main()
{
    int T, n, k;
    ll x;
    cin >> T;
    for (int i = 1; i <= T; ++i) {
        S.init();
        scanf("%d", &n);
        while (n--) S.insert(x);
        S.rebuild();
        scanf("%d", k);
        cout << S.query(k) << '\n';
    }
    return 0;

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值