• [HEOI2014]逻辑翻译(分治)


    题目描述
    在人类的神经系统中,每个信号都可以用?1或+1来表示。这些信号组合起来最后形成 了喜怒哀乐,酸甜苦辣,红黄绿蓝等各种各样的复杂信息。纳米探测科技的突破让生物学家 可以测量大脑中特定区域的完整逻辑功能。然而超大数据的处理一直是令 H 教授头疼的问 题。
     假设一个逻辑单元接受N个信号输入,并产生一个代表某种意义的实数值r。那么总共 可能的情况有2^N种。
    通过长时间的累积测量, H 教授可以准确地获得输入信号与r的关系表:
     f:{-1,1}N →R  然而进一步研究发现,神经元的运算方式可以被建模为人们熟知的多项式。由于一个输 入
    信号值的平方一定为1,所以我们可以用不含幂的2^N项的多项式来唯一表示任何一个逻辑f。 
    例如
     x1 = +1; x2 = +1   x1 = +1; x2 = -1  x1 = -1; x2 = +1 x1 = -1; x2 = -1
            0                   1                2                3  
    可以写成 f(x1,x2) = 1.5 - 0.5x2 - x1 研究一个逻辑单元的多项式形式对了解大脑工作十分有意义,于是
    小 M 决定帮 H 教授 把测量出的逻辑关系表全部转换成多项式的形式。这么简单的工作一定难不倒编程能手
    小M 的吧? 
    题解
    这题意思是给多项式的点值表达,让你把系数求出来。
    关键是它的多项式很鬼畜,有x1,x2,还有x1,x2让人感觉很烦。
    对于这么一个多项式a1+a2x1+a3x2+a4x1x2,我们把x1提出来,式子就变成了x1(a2+a4x2)+a1+a3x2。
    把x1去掉,加号两边的东西是不是长得很像?
    我们令两个点值表达只有x1不同,x1=-1时值为a,x1=1时值为b,那么左边那一坨就是(b-a)/2,右边那一坨就是(a+b)/2。
    于是我们成功的把问题规模减小了一半。
    其实这个思路和FFT几乎一模一样。
    然后这道题的输出很诡异,要求字典序输出,可以用dfs实现。
    还有我的操作有些鬼畜,导致最后分治出的序列和答案序列不一样,所以我又nlogn模拟了一遍把答案顺序排好。。
    代码
    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int N=(1<<21)+10;
    double x;
    int n,top,p[N];
    char s[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }    
    ll gcd(ll x,ll y){if(x<0)x=-x;if(y<0)y=-y;return y?gcd(y,x%y):x;}
    struct fs{
        ll x,y;
        fs operator +(const fs &b)const{
            ll xx=x*b.y+y*b.x,yy=y*b.y*2;
            ll g=gcd(yy,xx);
            xx/=g;yy/=g;
            return fs{xx,yy};
        }
        fs operator -(const fs &b)const{
            ll xx=x*b.y-y*b.x,yy=y*b.y*2;
            ll g=gcd(yy,xx);
            xx/=g;yy/=g;
            return fs{xx,yy};
        } 
    }dp[N];
    void dfs(int num,int x){
        if(num>n)return;
        p[++top]=x|(1<<num-1);
        dfs(num+1,x|(1<<num-1));dfs(num+1,x);
    }
    int main(){
        n=rd();
        for(int i=0;i<(1<<n);++i){
          int o=0;scanf("%s%lf",s+1,&x);
          for(int j=1;j<=n;++j){
              o<<=1;o|=(s[j]=='+'?1:0);
          }
          if(x>0)dp[o].x=(int)(x*100+0.1);//因为要向0取整,所以要判断正负 
          else dp[o].x=(int)(x*100-0.1);
          dp[o].y=100;
          ll g=gcd(dp[o].x,dp[o].y);
          dp[o].x/=g;dp[o].y/=g;
        }
        for(int i=(1<<n-1);i>=1;i>>=1)
          for(int j=0;j<(1<<n);j+=(i<<1))
            for(int k=0;k<i;++k){
                fs x=dp[k+j],y=dp[k+i+j];
                dp[k+j]=y-x;dp[k+i+j]=x+y;       
            }
        for(int i=0;i<(1<<n);++i){
            int x=i,l=0,r=(1<<n)-1;
            while(l!=r){
                int mid=(l+r)>>1;
                if(x&1)r=mid;else l=mid+1;x>>=1;
            }
            if(l<i)swap(dp[l],dp[i]);
        }
        dfs(1,0);
        for(int i=0;i<(1<<n);++i){
            int x=p[i];
            if(!dp[x].x)continue;
            if(dp[x].y<0)dp[x].y=-dp[x].y,dp[x].x=-dp[x].x;
            if(dp[x].y!=1)
            printf("%lld/%lld ",dp[x].x,dp[x].y);
            else printf("%lld ",dp[x].x);
            for(int j=1;j<=n;++j)if(x&(1<<j-1))printf("x%d",j);
            printf("
    ");
        }
        return 0;
    }
     
  • 相关阅读:
    java学习笔记4对象的初始化与回收
    java学习笔记2数据类型、数组
    java学习笔记3类与对象的基础
    java学习笔记5类的方法
    java学习笔记1开发环境平台总结
    BZOJ 4843
    SPOJ TTM
    BZOJ 4154
    POJ 3680
    半平面交模板 HDU 1469
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10164411.html
Copyright © 2020-2023  润新知