题解 P4106 【[HEOI2014]逻辑翻译 】

ywy_c_asm

2018-12-11 09:32:57

Solution

首先这题我们发现输入的是一种类似二进制数的东西,输出的也是一种类似二进制数的东西,我们把这两个玩意分析一下。 例如$n=3$的时候输入的会有$2^3$种+-的组合: ```cpp --- --+ -+- -++ +-- +-+ ++- +++ ``` 而输出的多项式也会有$2^3$种,不过这就跟上面的不一样了,它们相当于从全集$x_1x_2x_3$选出的所有子集: $1$ $x_1$ $x_2$ $x_3$ $x_1x_2$ $x_1x_3$ $x_2x_3$ $x_1x_2x_3$ 然后我们回归正题,考虑他让我们求的多项式: $f(x_1,x_2,x_3)=a_0+a_1x_1+a_2x_2+a_3x_3+a_4x_1x_2+a_5x_1x_3+a_6x_2x_3+a_7x_1x_2x_3$ 显然做这题从二进制位的角度为突破口是一个不错的选择。我们知道二进制数有个挺好的性质就是位是互相独立的对吧,假如我们当前在最高位,显然会有一半的二进制数在这一位是1,把这些数的最高位上的1剥掉之后就跟剩下的一半一模一样了。 我们把这东西的性质套到这个“二进制项”(这一项有这个变量,那一位就是1,否则就是0,也是相当于二进制数)的多项式里来,我们钦定$x_1$为最高位,那么把上面那个多项式变一下形就是: $f(x_1,x_2,x_3)=a_0+a_2x_2+a_3x_3+a_6x_2x_3+x_1(a_1+a_4x_2+a_5x_3+a_7x_2x_3)$ (如果你学过FFT或者FWT的话对这个应该是不会陌生的,没学过的建议去学一下再来做这题……) 咦,如果抛去$x_1$不管的话,我们就得到了两个形式一样的多项式?规模好像还减半了? 那么很自然的就能想到一个递归分治的过程,我们递归到最底层只剩常数项的时候,这些系数就自然的出来了,甚至都不用回溯。 然而我们现在的问题是:如何“抛去$x_1$不管”? 其实我们到现在为止还只利用了这题的一半性质,要知道,他给你的那堆关系里,$x_{\text{啥}}$的系数都是$1\space or\space -1$啊。 那么我们假设在递归的时候能够维护当前的这一堆关系,考虑咱们划分这个多项式的过程,左边的就不能有$x_1$,右边的虽然带着$x_1$但是跟没有一样,那么我们不妨把这堆关系也按照$x_1$划分一下,$x_1=1$的划成一堆,记为$A$,$x_1=-1$的划成一堆,记为$B$,然后我们将$x_1$分别代入,这个时候不考虑系数的话$B$的每一项都相当于$A$取反了,那么就把$\frac{A+B}{2}$就是把$x_1$的影响完全消掉了划到递归的左边去,把$\frac{A-B}{2}$就是把$x_1$的影响搞成1划到递归的右边去。 好,做完了。 另外这题的输出极为恶心,建议写个dfs输出,另外建议自行把$x_1,x_2……x_n$他们怎么进行二进制表示组织好,这题细节问题还是挺多的。 ```cpp #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define abs(_o) ((_o<0)?-(_o):_o) #define ll long long using namespace std; namespace ywy{ inline int get(){ char c;int n=0; while((c=getchar())||23333)if(c=='-'||c=='+')break; n=(n<<1)|(c=='+'); while((c=getchar())||23333){ if(c=='+'||c=='-')n=(n<<1)|(c=='+'); else return(n); } } inline ll gcd(ll a,ll b){ if(a<0)a=-a; if(b<0)b=-b; while(b){ ll r=a%b;a=b;b=r; } return(a); } inline int Int(double n){ int down=(int)abs(n),up=down+1; if(abs(abs(n)-down)<abs(abs(n)-up))return((n<0)?-down:down); return((n<0)?-up:up); } void print(ll num){ if(num<0)putchar('-'),num=-num; if(num>=10)print(num/10); putchar(num%10+'0'); } typedef struct _fs{ ll a;ll b; _fs(){}_fs(ll i,ll j){a=i;b=j;} _fs(double n){ a=Int(n*100);b=100;wh(); } friend _fs operator *(const _fs &a,const _fs &b){ ll cjr=a.a*b.a,ywy=a.b*b.b; ll r=gcd(cjr,ywy); cjr/=r;ywy/=r; return(_fs(cjr,ywy)); } inline void wh(){ ll r=gcd(a,b);a/=r;b/=r; if(b<0)a=-a,b=-b; } friend _fs operator /(const _fs &a,const int &b){ _fs cjr=a;cjr.b*=b; cjr.wh();return(cjr); } friend _fs operator +(const _fs &a,const _fs &b){ _fs cjr=_fs(a.a*b.b+b.a*a.b,a.b*b.b);cjr.wh();return(cjr); } friend _fs operator -(const _fs &a,const _fs &b){ _fs cjr=_fs(a.a*b.b-b.a*a.b,a.b*b.b);cjr.wh();return(cjr); } inline void print(){ wh();if(b==1)ywy::print(a);else ywy::print(a),putchar('/'),ywy::print(b); } }fs;fs poly[1048577]; inline void fwt(int n){ for(register int bit=n;bit>1;bit>>=1){ for(register int i=0;i<n;i+=bit){ for(register int j=i;j<i+(bit>>1);j++){ fs ywy=poly[j],cjr=poly[j+(bit>>1)]; poly[j]=(ywy+cjr)/2; poly[j+(bit>>1)]=(cjr-ywy)/2; } } } } int n; inline void pr(int id){ int cnt=1;for(register int i=n-1;i>=0;i--){ if(id&(1<<i))putchar('x'),print(cnt);cnt++; } } unsigned char printed[1049576]; void dfs(int now,int deep,unsigned char is1){ if(deep==-1){ if(poly[now].a&&!printed[now]){ poly[now].print();putchar(' ');pr(now);putchar('\n'); } printed[now]=1;return; }if(is1&&!printed[now]){ printed[now]=1; if(poly[now].a){ poly[now].print();putchar(' ');pr(now);putchar('\n'); } } dfs(now|(1<<deep),deep-1,1); dfs(now,deep-1,0); } void ywymain(){ cin>>n;for(register int i=0;i<(1<<n);i++){ int id=get();double d;scanf("%lf",&d);poly[id]=_fs(d); } fwt(1<<n);dfs(0,n-1,1); } } int main(){ ywy::ywymain();return(0);//再见程序 } ```