小凱學數學
阿新 • • 發佈:2018-11-01
題解:
有點類似於區間DP,一個大區間是由它的子區間合併而來,那麼遞推很顯然,舉個例子吧,合併1到3是由1-1和2-3,1-2和3-3轉移過來的。先預處理出小凱運算,然後初始化f(i,i)為1,一個f裡面是一個bool陣列,儲存這個區間合併可能得到的結果,從小到大列舉區間起點,區間長度和區間斷點,最後答案為f(1,n)中有的數。
考試時沒仔細看題,把a的範圍看成了1到7,痛失80分。
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #define MAXA 705 using namespace std; struct Rx { bool Vis[8]; }f[MAXA][MAXA]; int K[10][10],n,a[MAXA]; vector<int> Ans; void Merge(int L1,int R1,int L2,int R2) { for(int i=0;i<=7;i++) { if(f[L1][R1].Vis[i]) for(int j=0;j<=7;j++) { if(f[L2][R2].Vis[j]) { int k = K[i][j]; if(!f[L1][R2].Vis[k]) f[L1][R2].Vis[k] = 1; } } } } int main() { // freopen("math.in","r",stdin); // freopen("math.out","w",stdout); for(int i=0;i<=7;i++) for(int j=0;j<=7;j++) K[i][j] = ((i & j) + (i | j)) >> 1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); f[i][i].Vis[a[i]] = 1; } for(int j=0;j<n;j++) for(int i=1;i+j<=n;i++) { for(int k=i;k<i+j;k++) { Merge(i,k,k+1,i+j); } } for(int i=0;i<=7;i++) if(f[1][n].Vis[i]) Ans.push_back(i); for(int i=0;i<Ans.size()-1;i++) printf("%d ",Ans[i]); printf("%d",Ans[Ans.size()-1]); }