-
题意:t个测试样例,每次输入一个数n,求n最少能由几个3的倍数的数相或得到
-
思路:首先,如果n可以被3整除,直接输出n即可。
如果n不能被3整除,将n写成2进制,如果某一位上为1,则说明他对n具有贡献度,每一位上对3取余不是1就是2,这些余数加起来等于n对3取余所得的余数。现在就是要在这些1中取一些,使取的这些1对3取余所得的余数和为0,且两次取完后包含所有的1。可以考虑贪心的思想,注意分情况。
如果n%3=1,即需要在n的基础上少取1+s*3就行,如果对3取余等于1的位大于等于2,就可以通过不取1个这样的1来构造;如果对3取余等于1的位等于1 ,则可以一个不取这样的数,另一个通过不取两个余2的位来构造;如果没有对3取余为1的位,则构造的两个数都要通过选取不取两个余2的位来构造。
如果n%3=2,同理
举个栗子:n=29;
对应的二进制为:1 1 1 0 1
每一位对应的数为:16 8 4 0 1
每一位对3取余余数为:1 2 1 0 1
n%3=2
余2的数只有1个,那么一个数这么构造1 0 1 0 1,等于21
另一个数为1 1 0 0 0,等于24 -
完整代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int a[100005];
ll two[100005];
int dis[100005];
vector<int> v[10];
int main(){
int t;
cin>>t;
two[0]=1;
dis[0]=1;
for(int i=1;i<1000;i++){//预处理
two[i]=two[i-1]*2;
dis[i]=two[i]%3;
}
ll n,m;
// m=2;
while(t--){
//m++;
cin>>m;
n=m;
int i=0,l;
for(i=0;i<4;i++){
v[i].clear();
}
i=0;
while(n>0){
a[i]=n%2;
n=n/2;
i++;
}
l=i;
for(i=0;i<l;i++){
if(a[i]==1&&dis[i]==1){
v[1].push_back(i);
}
else if(a[i]==1&&dis[i]==2){
v[2].push_back(i);
}
}
if(m%3==0){
printf("1 %lld\n",m);
}
else if(m%3==1){
ll ans=0,ans1=0;
if(v[1].size()>1){
for(i=0;i<(int)(v[1].size())-1;i++){
ans=ans+two[v[1][i]];
}
for(i=1;i<(int)(v[1].size());i++){
ans1=ans1+two[v[1][i]];
}
for(i=0;i<v[2].size();i++){
ans=ans+two[v[2][i]];
ans1=ans1+two[v[2][i]];
}
}
else if(v[1].size()==1){
for(i=0;i<v[2].size();i++){
ans=ans+two[v[2][i]];
}
for(i=0;i<v[1].size();i++){
ans1=ans1+two[v[1][i]];
}
for(i=0;i<(int)(v[2].size())-2;i++){
ans1=ans1+two[v[2][i]];
}
}
else {
for(i=0;i<(int)(v[2].size())-2;i++){
ans1=ans1+two[v[2][i]];
}
for(i=2;i<v[2].size();i++){
ans=ans+two[v[2][i]];
}
}
printf("2 %lld %lld\n",ans,ans1);
}
else if(m%3==2){
ll ans=0,ans1=0;
if(v[2].size()>=2){
for(i=0;i<v[1].size();i++){
ans=ans+two[v[1][i]];
ans1=ans1+two[v[1][i]];
}
for(i=0;i<(int)(v[2].size())-1;i++){
ans1=ans1+two[v[2][i]];
}
for(i=1;i<v[2].size();i++){
ans=ans+two[v[2][i]];
}
}
else if(v[2].size()==0){
for(i=0;i<(int)(v[1].size())-2;i++){
ans=ans+two[v[1][i]];
}
for(i=2;i<(int)(v[1].size());i++){
ans1=ans1+two[v[1][i]];
}
}
else if(v[2].size()==1){
for(i=0;i<v[2].size();i++){
ans=ans+two[v[2][i]];
}
for(i=2;i<(int)(v[1].size());i++){
ans=ans+two[v[1][i]];
}
for(i=0;i<v[1].size();i++){
ans1=ans1+two[v[1][i]];
}
}
printf("2 %lld %lld\n",ans,ans1);
}
}
}