[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
*/

 

posted @ 2019-01-11 21:57  *Miracle*  阅读(275)  评论(0编辑  收藏  举报