zoukankan      html  css  js  c++  java
  • P4574 [CQOI2013]二进制A+B

    传送门

    思路:

      本题可用数位DP来做,设 f [ i ][ a ][ b ][ c ][ j ] 表示当前枚举到(二进制下的)第i位,a' b' c'各用a,b,c了几个1,j表示最后一位是否有进位。转移方程就只要暴力枚举8种情况(不同位置及是否进位)。

    DP方程:

    inline void dp()//动态规划,强行枚举八种情况 
    {
        f[0][0][0][0][0]=0;
        for (int i=0;i<n;++i)
            for (int j=0;j<=jla;++j)
                for (int k=0;k<=jlb;++k)
                    for (int l=0;l<=jlc;++l)
                    {
                        long long tmp=f[i][j][k][l][0];//枚举最后一位不进位的情况
                        f[i+1][j+1][k+1][l+1][1]=min(f[i+1][j+1][k+1][l+1][1],tmp+(1<<i+1));
                        f[i+1][j+1][k][l+1][0]=min(f[i+1][j+1][k][l+1][0],tmp+(1<<i));
                        f[i+1][j][k+1][l+1][0]=min(f[i+1][j][k+1][l+1][0],tmp+(1<<i));
                        f[i+1][j][k][l][0]=min(f[i+1][j][k][l][0],tmp);
                        tmp=f[i][j][k][l][1];//枚举最后一位进位的情况
                        f[i+1][j+1][k+1][l+1][1]=min(f[i+1][j+1][k+1][l+1][1],tmp+(1<<i+1));
                        f[i+1][j][k+1][l][1]=min(f[i+1][j][k+1][l][1],tmp+(1<<i));
                        f[i+1][j+1][k][l][1]=min(f[i+1][j+1][k][l][1],tmp+(1<<i));
                        f[i+1][j][k][l][0]=min(f[i+1][j][k][l][0],tmp);
                    }
    }

      由上DP转移方程可看出,如果是枚举最后一位进位的情况,则需要转移到不进位的DP方程。因为二进制是逢二进一,最后一位如果为1,且进位,就要变为0;如果是从不进位开始转移,则与进位相反。

    完整代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define INF 0x7f7f7f7f7f7f7f
    int T,a,b,c;
    int n,jla,jlb,jlc;//n记录三个数的二进制数码长度的最大值,jla、jlb、jlc分别记录a、b、c的二进制数码中 1 的个数
    long long f[33][33][33][33][2];
    inline int read()//快读 
    {
        char kr=0;
        char ls;
        for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
        int xs=0;
        for(;ls>='0'&&ls<='9';ls=getchar())
        {
            xs=xs*10+ls-48;
        }
        if(kr=='-') xs=0-xs;
        return xs;
    }
    inline int lowbit(int x)//求出x的二进制数码中 1 的个数
    {
        int sum=0;
        for (;x;x>>=1)
            sum+=x&1;
        return sum;
    }
    inline void dp()//动态规划,强行枚举八种情况 
    {
        f[0][0][0][0][0]=0;
        for (int i=0;i<n;++i)
            for (int j=0;j<=jla;++j)
                for (int k=0;k<=jlb;++k)
                    for (int l=0;l<=jlc;++l)
                    {
                        long long tmp=f[i][j][k][l][0];//枚举最后一位不进位的情况
                        f[i+1][j+1][k+1][l+1][1]=min(f[i+1][j+1][k+1][l+1][1],tmp+(1<<i+1));
                        f[i+1][j+1][k][l+1][0]=min(f[i+1][j+1][k][l+1][0],tmp+(1<<i));
                        f[i+1][j][k+1][l+1][0]=min(f[i+1][j][k+1][l+1][0],tmp+(1<<i));
                        f[i+1][j][k][l][0]=min(f[i+1][j][k][l][0],tmp);
                        tmp=f[i][j][k][l][1];//枚举最后一位进位的情况
                        f[i+1][j+1][k+1][l+1][1]=min(f[i+1][j+1][k+1][l+1][1],tmp+(1<<i+1));
                        f[i+1][j][k+1][l][1]=min(f[i+1][j][k+1][l][1],tmp+(1<<i));
                        f[i+1][j+1][k][l][1]=min(f[i+1][j+1][k][l][1],tmp+(1<<i));
                        f[i+1][j][k][l][0]=min(f[i+1][j][k][l][0],tmp);
                    }
    }
    inline void clear()//为做DP初始化 
    {
        memset(f,INF,sizeof(f)); 
        n=max((int)log2(a)+1,(int)log2(b)+1);
        n=max(n,(int)log2(c)+1);//求 n 
        jla=lowbit(a),jlb=lowbit(b),jlc=lowbit(c);
    }
    int main()
    {
        a=read();b=read();c=read();
        clear();
        dp();
        if(f[n][jla][jlb][jlc][0]>=INF)//注意是“≥INF” 
        {
            printf("-1
    ");
            return 0;
        }//如果无解就输出-1 
        printf("%lld
    ",f[n][jla][jlb][jlc][0]);//输出最小值 
        return 0;
    }

    一些注意事项:

     ①本题的 f 数组要开long long 不然会爆。

     ②INF也要尽量开大。

     ②在判断无解时要判 " ≥ INF ”(因为转移过程中会加上部分的值)   

    其他的一些细节瞎搞搞就AC了。

  • 相关阅读:
    硬盘
    [编译] 6、开源两个简单且有用的安卓APP命令行开发工具和nRF51822命令行开发工具
    [编译] 5、在Linux下搭建安卓APP的开发烧写环境(makefile版)—— 在Linux上用命令行+VIM开发安卓APP
    [Zephyr] 1、在linux上安装Zephyr-OS并跑DEMO
    [编译] 4、在Linux下搭建nRF51822的开发烧写环境(makefile版)
    [BlueZ] 2、使用bluetoothctl搜索、连接、配对、读写、使能notify蓝牙低功耗设备
    [BlueZ] 1、Download install and use the BlueZ and hcitool on PI 3B+
    [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)
    [ARCH] 1、virtualbox中安装archlinux+i3桌面,并做简单美化
    [编译] 3、在Linux下搭建51单片机的开发烧写环境(makefile版)
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9665321.html
Copyright © 2011-2022 走看看