P14266 [ROI 2015 Day2] 保护野生动物
好久没写题解了啊……上次写题解居然已经是去年了。
数位 DP。
设
注意到
转移方式为:枚举有多少个数这一位为
令二进制下
code:
#include<bits/stdc++.h>
using namespace std;
const int N=65;
int T;
long long n,dp[N][3],ans[4];
pair<int,int> p[N][3];
long long read(){
long long k=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9'){
k=k*10+ch-'0';
ch=getchar();
}
return k;
}
int main(){
T=read();
while(T--){
n=read();
memset(dp,0xcf,sizeof dp);
if(n&1){
dp[0][0]=0;
p[0][0]={1,0};
dp[0][1]=1;
p[0][1]={3,0};
}
else{
dp[0][0]=0;
p[0][0]={0,0};
dp[0][1]=0;
p[0][1]={2,0};
}
n>>=1;
int L=0;
while(n){
int nw=(n&1);
n>>=1;
++L;
for(int i(0);i<=3;++i){
for(int j(0);j<=2;++j){
if(((i+j)&1)!=nw)continue;
long long val=dp[L-1][j]+(i==3)*(1ll<<L);
if(val>dp[L][(i+j)/2]){
dp[L][(i+j)/2]=val;
p[L][(i+j)/2]={i,j};
}
}
}
}
ans[1]=0;ans[2]=0;ans[3]=0;
for(int i(L),nw(0);i>=0;--i){
// cout<<i<<" p[i][nw] "<<p[i][nw].first<<" "<<p[i][nw].second<<'\n';
for(int j(p[i][nw].first);j;--j)ans[j]+=(1ll<<i);
nw=p[i][nw].second;
}
printf("%lld %lld %lld\n",ans[1],ans[2],ans[3]);
}
return 0;
}