二进制

12 篇文章 0 订阅
2 篇文章 0 订阅

题目

这里写图片描述
这里写图片描述

过程

这是上午考试的第四题。当时自己读完题后,看了数据规模,感觉是故意设计的(本来就是嘛),但是又实在没有方法,就只好打了一个两个dfs嵌套的暴力。。结果(猜也能猜出来):WA×5,TLE×5。
正解:dp。(什么?这破题居然能dp?)
思路:首先预处理出所有的情况,然后O(1)输出。
dp数组开成[32][32][32][32][2]大小,f[l][i][j][k][jin]表示Z的长度最大为l、X a(2) 中1的数量为i、Y a(2) 中1的数量为j、Z a(2) 中1的数量为k、进位为jin的最小的符合条件的答案(没有为-1)。
枚举l、i、j、k、jin以后,如果情况成立,我们用p、q、r分别枚举X、Y、Z的下一位,若情况仍成立,那么我们就可以进行状态转移。状态转移方程如下:

if(f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]==-1||f[l][i][j][k][jin]+r*(1<<l)<f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2])
f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]=f[l][i][j][k][jin]+r*(1<<l);

其中,l+1为新生成的Z的长度,i+p、j+q、k+r不必说,(p+q+jin-r)/2为新产生的Z的进位。为什么呢?因为p+q+jin更新了Z,r为新生成的Z的个位,减去r再整除2即为新的Z在二进制下的余数。
其余的请见代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,a,b,c,g1,g2,g3,l1,l2,l3,i,len;
int f[32][32][32][32][2];
void init(int n,int &length,int &ge)
{
    length=ge=0;
    while(n)
    {
        if(n%2) ge++;
        n>>=1;
        length++;
    }
}
void dp()
{
    memset(f,-1,sizeof(f));
    f[0][0][0][0][0]=0;
    for(int l=0;l<=30;l++)
      for(int i=0;i<=30;i++)
        for(int j=0;j<=30;j++)
          for(int k=0;k<=30;k++)
            for(int jin=0;jin<=1;jin++)
              if(f[l][i][j][k][jin]>=0)
                for(int p=0;p<=1;p++)
                  for(int q=0;q<=1;q++) 
                    for(int r=0;r<=1;r++)
                      if((p+q+jin)%2==r)
                        if(f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]==-1||f[l][i][j][k][jin]+r*(1<<l)<f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2])
                          f[l+1][i+p][j+q][k+r][(p+q+jin-r)/2]=f[l][i][j][k][jin]+r*(1<<l);
}
main()
{
    freopen("binary.in","r",stdin);
    freopen("binary.out","w",stdout);
    dp();
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        init(a,l1,g1);
        init(b,l2,g2);
        init(c,l3,g3);
        len=max(l1,max(l2,l3));
        printf("%d\n",f[len][g1][g2][g3][0]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值