• 【清华集训2014】玛里苟斯


    看到这道题,然后便错误地联想到了数位DP什么的……接着发现了答案在一个界内,然后就想着暴力了。

    首先如果对每一位都设一个变量的话,根据插板法,最多只能有1e7个项对答案有贡献,和答案在一个界内这个条件组合起来,这启发我们去想暴力。

    首先非基变量是没有用的,考虑它们的选和不选,最后都要除掉。

    所以只有基变量有贡献。

    显然基变量越多跑的越慢,这个时候设基变量有 (b) 个,很明显可以得到答案的一个粗略的下界

    [frac{sum_{i=0}^{2^{b-1}} i^k}{2^{b-1}} ]

    首先上面是一个自然幂数前缀和,显然是一个 (k+1) 项的多项式,忽略常数带来的影响,除掉分母,令 (x = 2^b),可得

    [x ^ k le 2^{63} ]

    也就是说,$ b leq log_2 sqrt[k]{2^{63}} $,易得 (k geq 3) 的时候是可以暴力枚举基的。

    那么只剩下 (k = 1)(2) 了。

    考虑 (k = 1),只要按位考虑贡献即可。

    考虑 (k = 2),对于平方,只是同一种方案对每两个位的值进行乘积后求和。所以需要同时考虑两位。

    因为单个变量 (0)(1) 是相同的,所以考虑分别乘个 (frac{1}{2}) 即可。

    拆一下式子枚举变量即可。注意 (k = 2) 时只有 (frac{1}{2}) 的判定不是下标相同(虽然式子拆出来是这样的),而是在基张成的线性空间里每个向量这两位都相同。即基向量矩阵中这两行相等。

    计算过程可以用 __int128 所以没什么问题,long double 会掉精度。

    所以还是一道简单题,但我还是爆OJ了。

    #include <bits/stdc++.h>
    
    typedef unsigned long long LL;
    typedef __int128 H;
    LL lb[64], bss[64], mat[64];
    int n, K, bak;
    void insert(LL v) {
    	for (int i = 63; ~i; --i)
    		if (v >> i & 1) {
    			if (lb[i]) v ^= lb[i];
    			else { lb[i] = v; break; }
    		}
    }
    LL fnd(LL x) {
    	LL res = 0;
    	for (int i = 63; ~i; --i)
    		if (lb[i] & x)
    			res |= 1llu << i;
    	return res;
    }
    H fastpow(H a, int px) {
    	H res = 1;
    	while (px --> 0) res *= a;
    	return res;
    }
    H haans;
    void dfs(int now, LL v) {
    	if (now == bak) {
    		haans += fastpow(v, K);
    		return ;
    	}
    	dfs(now + 1, v);
    	dfs(now + 1, v ^ bss[now]);
    }
    int main() {
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	std::cin >> n >> K;
    	LL t;
    	for (int i = 1; i <= n; ++i) std::cin >> t, insert(t);
    	for (int i = 0; i < 64; ++i) if (lb[i]) bss[bak++] = lb[i];
    	H ans = 0; LL app = 0;
    	for (int i = 0; i != 64; ++i) app |= lb[i];
    	if (K >= 3) dfs(0, 0), ans = haans >> bak - 1;
    	else if (K == 2) {
    		for (int i = 0; i != 64; ++i) mat[i] = fnd(1llu << i);
    		for (int i = 0; i != 64; ++i) if (app >> i & 1)
    			for (int j = 0; j != 64; ++j) if (app >> j & 1)
    				ans += (H) (1llu << i) * (1llu << j) * (1 << (mat[i] == mat[j]));
    		ans >>= 1;
    	} else ans = app;
    	LL ax = ans;
    	std::cout << (ax >> 1);
    	if (ax & 1) std::cout << ".5";
    	std::cout << std::endl;
    	return 0;
    }
    
  • 相关阅读:
    stm32 IO模式
    stm32的ADC
    bsp
    stm32的硬件调试设置
    RTC实时时钟
    快手2019笔试题 “回文子串" 解题思路
    C++内存修改器开源代码
    FC游戏修改教程(hack)小白文。
    GLFW+GLEW搭建opengl环境(备忘)
    8086 IO读写操作
  • 原文地址:https://www.cnblogs.com/daklqw/p/11515486.html
Copyright © 2020-2023  润新知