• [HEOI2014]逻辑翻译


    ywy_c_asm的良心题解

    是道好题

    体现了二进制位的形象递归思想,以及将FWT的思路(都是拆位分治)用到题目中的典范

    可以暴力高斯消元。完全没有利用2^N以及+-1的良好性质

    发现项数,方程和二进制位有关系

    考虑类似FWT,FFT能不能递归?

    已经具备递归的模式

    但是怎样递归下去?
    消掉x1的话,对应的位置,1010,0010,相加除以2,相减除以2,分别作为两边递归下去的答案,即可。

    这样,通过化简规模,最终到了边界就可以直接得到解。

    细节比较多

    1.我是+用1,-用0,选择1用1,选择0用0,最后使得项数下标和最后选择的方程下标一致,直接得到答案

    2.输出恶心,还是分治。注意别重复输出。其实写的好看一点,本质是线段树的x<<1,x<<1|1

    3.读入double,不要强转int,可能是0.999999999999999,所以,x=round(100*df),四舍五入即可。

    4.为了卡常,必须快输。

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    int n;
    int gcd(int a,int b){
        return b?gcd(b,a%b):a;
    }
    struct node{
        int u,d;
        node(){}
        node(ll s,ll m){
            u=s;d=m;
        }
        node friend operator +(node a,node b){
            return node(a.u+b.u,a.d);
        }
        node friend operator -(node a,node b){
            return node(a.u-b.u,a.d);
        }
        node friend operator *(node a,ll b){
            return node(a.u*b,a.d);
        }
        node friend operator /(node a,ll b){
            return node(a.u,a.d*b);
        }
        void op(){
            if(u<0) putchar('-'),u=-u;
            int g=gcd(u,d);
            u/=g;d/=g;
            printf("%d",u);
            if(d!=1) printf("/%d",d);
        }
    }c[1<<20];//,f[1<<20],g[1<<20];
    char s[233];
    void get(){
        scanf("%s",s);
        int to=0;
        for(reg i=0;i<n;++i){
            if(s[i]=='+') to+=(1<<i);
        }
        double df;
        scanf("%lf",&df);
        c[to].d=100;c[to].u=round(df*100.0);
    }
    void div(int l,int r,int to,int cnt){
        if(cnt==n){
            //f[to]=c[to];
            return;
        }
        int mid=(l+r)>>1;
        for(reg i=0;i<(1<<(n-cnt-1));++i){
            int t1=(i<<(cnt+1))|(to)|(1<<cnt);
            int t0=(i<<(cnt+1))|(to);//|(1<<cnt)
            node tmp=c[t1];
            c[t1]=(tmp-c[t0])/2;
            c[t0]=(tmp+c[t0])/2;
        }
        div(l,mid,to,cnt+1);
        div(mid+1,r,to|(1<<cnt),cnt+1);
    }
    bool has[1<<20];
    void op(int s){
        if(has[s]) return;
        has[s]=1;
        if(c[s].u==0) return;
        c[s].op();
        putchar(' ');
        for(reg i=0;i<n;++i){
            if(s&(1<<i)){
                printf("x%d",i+1);
            }
        }
        puts("");
    }
    void out(int l,int r,int to,int cnt){
        if(cnt==n-2){
            op(to);op(to|(1<<cnt));op(to|(1<<cnt)|(1<<(cnt+1)));op(to|(1<<(cnt+1)));
            return;
        }
        if(!has[to])op(to);
        int mid=(l+r)>>1;
        out(l,mid,to|(1<<cnt),cnt+1);
        out(mid+1,r,to,cnt+1);
    }
    int main(){
        rd(n);    
        for(reg i=0;i<(1<<n);++i) get();
    //    for(reg i=0;i<(1<<n);++i){
    //        cout<<c[i].u<<" "<<c[i].d<<endl;
    //    }
        div(0,(1<<n)-1,0,0);
        if(n==1){
            op(0);op(1);return 0;
        }
        out(0,(1<<n)-1,0,0);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/11 19:21:58
    */
  • 相关阅读:
    Navicat Premium15安装与激活
    JDK13.0.1安装与环境变量的配置(Win10平台为例)
    Linux系统手动安装Firefox浏览器
    Debian 9.5 解决中文显示乱码
    debian 安装后需做的几件事
    Windows10 Linux子系统安装图形化界面的两种方法及其对比
    线程池大小设置,CPU的核心数、线程数的关系和区别,同步与堵塞完全是两码事
    Java学习笔记八(反射)
    高速排序法(一)
    Java深入
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10257576.html
Copyright © 2020-2023  润新知