XOR Inverse

给定数组a,求一个x,使得数组每个数异或x得到新数组b,b的逆序对数量最少。如果有多个x符合条件,求最小的x。
链接:XOR Inverse
思路:
从二进制角度来看,从最高位开始,如果两个数数位相同,则继续往下看,当数位不同时,两个数就分出了大小,0小1大,那么就会产生顺序对或者是逆序对。当前位如果异或了1之后,顺序对就变成了逆序对,逆序对就变成了顺序对。
所以30 * n logn的做法是:
从二进制最高位开始枚举,判断此时x这一位填1,是否会得到逆序数更小的数组,不断贪心。注意不要用树状数组求逆序对,要用归并排序。树状数组要离散化,慢了些。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5, mod = 1e9 + 7;
int a[N];
int b[N], c[N];
int merge(int l ,int r)
{
    if (l >= r) return 0;
    int mid = (l + r) >> 1;
    int ret = 0;
    ret += merge(l, mid);
    ret += merge(mid + 1, r);
    int i = l, j = mid + 1;

    int cnt = 0;
    while(i <= mid && j <= r)
    {
        if (b[i] <= b[j]) c[++cnt] = b[i++];
        else {
            ret += mid - i + 1;
            c[++cnt] = b[j++];
        }
    }
    while (i <= mid) c[++cnt] = b[i++];
	while (j <= r) c[++cnt] = b[j++];
    
    for (int k = 1, ll = l; k <= cnt; k++, ll++) b[ll] = c[k];
    return ret;
}
signed main ()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        b[i] = a[i];
    }
    int ans = merge(1, n);
    int x = 0;
    for (int k = 30; k >= 0; k--){
        x |= (1 << k);
        for (int i = 1; i <= n; i++) b[i] = a[i] ^ x;
        int temp = merge(1, n);
        if (temp >= ans) x ^= (1<<k);
        else ans = temp;
    }
    cout << ans << " " << x;
    return 0;
}

n logn的做法:
使用0 1字典树,在插入a[i]的时候,更新二进制第i位的顺序对和逆序对的情况,具体是这样更新的:已经匹配到第p位相同了,当前位是0,那么兄弟节点1的数目就是与0产生逆序对的数目,反之则是新产生顺序对的数目。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5, mod = 1e9 + 7;
int a[N];
int f[35][2], tree[N * 30][2];
int siz[N * 30];
int tot = 1;
void insert(int x)
{
    int p = 1;
    for (int i = 30; i >= 0; i--){
        int k = (x >> i) & 1;
        if (k == 0) f[i][0] += siz[tree[p][1]];
        else f[i][1] += siz[tree[p][0]];

        siz[p]++;
        if (tree[p][k] == 0) tree[p][k] = ++tot;
        p = tree[p][k];
    }
    siz[p]++;
}
signed main ()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        insert(a[i]);
    }
    int x = 0;
    int ans = 0;
    for (int i = 30; i >= 0; i--) {
        if (f[i][0] > f[i][1]) {
            ans += f[i][1];
            x |= (1 << i);
        }
        else ans += f[i][0];
    }
    cout << ans << " " << x;
    return 0;
}

比赛的时候能用第一种还是第一种吧,毕竟能ac又好写又是好想的套路,第二种真难想啊。

// decrypt_tool.cpp // 仅做解密并写出 shellcode_out.bin,不执行、不注入 #include <windows.h> #include <iostream> #include <fstream> #include <vector> #include <string> #include <sstream> #include <cryptopp/base64.h> #include <cryptopp/filters.h> #include <cryptopp/hex.h> #include <cryptopp/gcm.h> #include <cryptopp/aes.h> #include <cryptopp/filters.h> #include <cryptopp/secblock.h> #include <cryptopp/hkdf.h> #include <cryptopp/sha.h> #include "shellcode_b64.h" // 你已生成的头文件 using byte = unsigned char; // --- base64 decode string -> vector<byte> static std::vector<byte> b64_to_bytes(const std::string& b64) { std::string decoded; CryptoPP::StringSource ss(b64, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)) ); return std::vector<byte>(decoded.begin(), decoded.end()); } // --- write bytes to file static bool write_file(const std::string& path, const std::vector<byte>& data) { std::ofstream ofs(path, std::ios::binary); if (!ofs) return false; ofs.write(reinterpret_cast<const char*>(data.data()), data.size()); return true; } // --- derive AES-256 key from key material using HKDF-SHA256 static std::vector<byte> derive_aes_key_from_material(const std::vector<byte>& key_material) { std::vector<byte> out(32); CryptoPP::HKDF<CryptoPP::SHA256> hkdf; hkdf.DeriveKey(out.data(), out.size(), key_material.data(), key_material.size(), nullptr, 0, nullptr, 0); return out; } // --- AES-GCM decrypt (ciphertext includes only cipher; tag passed separately) static std::vector<byte> aes_gcm_decrypt( const std::vector<byte>& aes_key, const std::vector<byte>& iv, const std::vector<byte>& tag, const std::vector<byte>& ciphertext) { std::vector<byte> recovered; try { CryptoPP::GCM<CryptoPP::AES>::Decryption dec; dec.SetKeyWithIV(aes_key.data(), aes_key.size(), iv.data(), iv.size()); CryptoPP::AuthenticatedDecryptionFilter df(dec, new CryptoPP::VectorSink(recovered), CryptoPP::AuthenticatedDecryptionFilter::MAC_AT_END | CryptoPP::AuthenticatedDecryptionFilter::THROW_EXCEPTION, tag.size() ); // feed cipher then MAC at end df.ChannelPut("", ciphertext.data(), ciphertext.size()); df.ChannelPut("MAC", tag.data(), tag.size()); df.ChannelMessageEnd("MAC"); } catch (const CryptoPP::Exception& e) { std::cerr << "[ERROR] AES-GCM 解密或验证失败: " << e.what() << std::endl; return {}; } return recovered; } // --- multi-round XOR reverse. // xor_keys_b64: array of base64 strings in header (order: encryption order). // During encryption you likely applied keys in order k0, k1, k2. // For decryption you must apply XOR in reverse order again (XOR is its own inverse). static void multi_xor_reverse(std::vector<byte>& data, const char* xor_keys_b64[], int xor_key_count) { for (int k = xor_key_count - 1; k >= 0; --k) { std::vector<byte> key = b64_to_bytes(xor_keys_b64[k]); // decoded key bytes if (key.empty()) continue; size_t keylen = key.size(); for (size_t i = 0; i < data.size(); ++i) { data[i] ^= key[i % keylen]; } } } int main() { try { // 1) 从 header 读取 base64 编码的密文 (ciphertext),key_material, iv, tag, xor_keys[] std::string b64_cipher = std::string(b64_data); // base64 of ciphertext (not including tag) std::string b64_key_material = std::string(b64_key); // base64 of key material used to derive AES key std::string b64_iv = std::string(b64_iv); // base64 IV std::string b64_tag = std::string(b64_tag); // base64 tag // 2) decode std::vector<byte> ciphertext = b64_to_bytes(b64_cipher); std::vector<byte> key_material = b64_to_bytes(b64_key_material); std::vector<byte> iv = b64_to_bytes(b64_iv); std::vector<byte> tag = b64_to_bytes(b64_tag); if (ciphertext.empty()) { std::cerr << "[ERROR] ciphertext 解码为空,检查 shellcode_b64.h 中 b64_data 是否正确。\n"; return 1; } if (key_material.size() < 16) { std::cerr << "[WARN] key_material 看起来很短。确认 b64_key 内容是否正确。\n"; } // 3) derive AES key (HKDF SHA256) std::vector<byte> aes_key = derive_aes_key_from_material(key_material); // 4) AES-GCM 解密 (返回明文为经过 XOR 加密的二进制) std::vector<byte> after_aes = aes_gcm_decrypt(aes_key, iv, tag, ciphertext); if (after_aes.empty()) { std::cerr << "[ERROR] AES 解密失败或 tag 验证失败。\n"; return 1; } // 5) multi-round XOR reverse using xor_keys[] from header multi_xor_reverse(after_aes, xor_keys, xor_key_count); // 6) write output if (!write_file("shellcode_out.bin", after_aes)) { std::cerr << "[ERROR] 写出 shellcode_out.bin 失败。\n"; return 1; } std::cout << "[OK] 解密成功。输出: shellcode_out.bin\n"; std::cout << "请在受控、隔离的环境(虚拟机)中进行后续分析。\n"; return 0; } catch (const std::exception& ex) { std::cerr << "[EXCEPTION] " << ex.what() << std::endl; return 1; } } 我这个代码是不是没有实现或调试注入/执行到其他进程
最新发布
11-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值