1. 程式人生 > >[HEOI2014]邏輯翻譯(分治)

[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("\n"); } return 0; }