题意:给定一个 n (1 <= n <= 10^6),求(0 ^ p0) + (1 ^ p1) + (2 ^ p2) +…… + (n ^ pn) 的最大值,其中p0 ~ pn为 0 ~ n 中的数,且每个数只利用一次。
从n ~ 0枚举所有的数,对于每个数找它异或后得到二进制都是 1 的数或者 1 尽量多的数。
对于每个数,先找到与它二进制位数相同的全是 1 的数,然后把这个当成结果,与目前的数异或得到另一个数并记录,然后同时记录另一个数(可能用不到,但是为了节省时间)。
加起来的结果可能超int,故用long long。
#include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<cmath> #include<iostream> #include<sstream> #include<iterator> #include<algorithm> #include<string> #include<vector> #include<set> #include<map> #include<deque> #include<queue> #include<stack> #include<list> typedef long long ll; typedef unsigned long long llu; const int MAXN = 100 + 10; const int MAXT = 1000000 + 10; const int INF = 0x7f7f7f7f; const double pi = acos(-1.0); const double EPS = 1e-6; using namespace std; int n, ans[MAXT]; int main(){ scanf("%d", &n); memset(ans, -1, sizeof ans); for(int i = n; i >= 0; --i){ if(ans[i] != -1) continue; int k1 = log2(i) + 1; //求出其二进制位数,并加一位,为下一步作准备 int k2 = (1 << k1) - 1; //找与其位数相同的、二进制表示全为1的数 ans[k2 ^ i] = i; //记录 ans[i] = k2 ^ i; //记录 } ll sum = 0; for(int i = 0; i <= n; ++i) sum += ll(i ^ ans[i]); printf("%I64d\n", sum); for(int i = 0; i <= n; ++i){ if(i) printf(" "); printf("%d", ans[i]); } printf("\n"); return 0; }
时间: 2024-09-30 06:55:46