D-triples

题意

给你一个\(n\),问至少有几个数或运算起来可以等于\(n\),并且输出数量和这个几个数。题目说明给的\(n\)一定符合条件(不会输出\(n= 1\) 之类不存在情况)。

思路

  • 我们打个表就能知道n至少可以由\(1\)个或者\(2\)个数或起来。

  • 首先我们预先判断\(n \% 3 == 0\)这种输出\(n\)自己本身就可以了
  • 其它的数可以由\(2\)个数进行或运算得到。

    1. \(n\)转换为二进制,把每一位上1提取出来放到集合\(R\)
    2. 找到两个集合\(a、b\)\(a\cup b = R\)
      \(num1 = \sum_{i=0}^{a.size()} x_{i} (x_{i}\in a)\)
      \(num1 \% 3 == 0\)
      \(num2 = \sum_{i=0}^{b.size()} y_{i} (y_{i}\in b)\)
      \(num2 \% 3 == 0\)
    3. 再分别把\(a、b\)集合里的数加起来就是答案了。

样例(解决WA到哭的两个样例)

2
85
682
(1010101、1010101010)上面两个样例的二进制

AC代码

#include<bits/stdc++.h>
#define mes(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
int a[100];
int ans[3];

void solve(ll x){   //转换n为二进制
    int i = 0;
    while(x){
        a[i++] = x%2;
        x /= 2;
    }
}
int main(){
    int t;
    ll n;
    scanf("%lld", &t);
    while(t--){
        scanf("%lld", &n);
        if(n % 3ll == 0){
            printf("1 %lld\n", n);
            continue;
        }
        mes(a, 0);
        solve(n);
        ans[1] = ans[2] = 0;    //分别计算二进制位为1的数字取模3分别为1和2的数量
        for(int i = 0; i <= 64; i++){
            if(a[i] == 1){
                int num = (1ll<<i)%3ll;
                ans[num]++;
            }
        }
        int sum = ans[1] + ans[2]*2;
        int b[3][3];
        mes(b, 0);
        if(sum % 3 ==1){    //强行分组(本人比较菜只会这样写)
            if(ans[1] == 0){
                b[1][1] = 0;
                b[1][2] = ans[2] - 2;
                b[2][1] = 0;
                b[2][2] = 3;
            }
            else{
                b[1][1] = ans[1]-1;
                b[1][2] = ans[2];
                if(ans[2] == 0){
                    b[2][1] = 3;
                }
                else{
                    b[2][1] = 1;
                    b[2][2] = 1;
                }
            }
        }
        else if(sum %3 == 2){
            if(ans[2] == 0){
                b[1][1] = ans[1]-2;
                b[1][2] = 0;
                b[2][1] = 3;
                b[2][2] = 0;
            }
            else{
                b[1][1] = ans[1];
                b[1][2] = ans[2]-1;
                if(ans[1] == 0){
                    b[2][1] = 0;
                    b[2][2] = 3;
                }
                else{
                    b[2][1] = 1;
                    b[2][2] = 1;
                }
            }
        }
        ll num1 = 0, num2 = 0;
        for(int i = 0; i < 64; i++){
            if(a[i] == 1){
                int num = (1ll<<i)%3;
                if(b[2][num] == ans[num]){
                    num2 += (1ll<<i);
                    b[2][num]--;
                }
                if(b[1][num] > 0){
                    num1 += (1ll<<i);
                    b[1][num]--;
                }
                ans[num]--;
            }
        }
        printf("2 %lld %lld\n", num1, num2);
    }
    return 0;
}