今天的題都這麼。。。。
這道題後面會用到逆推。。。。
首先得判斷是否有合法方案。而且方案明顯會有很多種,但只需要統計算到這一位時答案有多少個1。
設f[i][j]表示算完i位時,答案裡有j個1.
考慮轉移,轉移時對答案產生影響的還有兩位間1位置的交集,也就是f[i][j]&a[i+1]後1的個數,設它為k。
交集中1個數就是
運算子是 & : k
運算子是 |:j+a[i+1]-k
運算子是 ^:j-a[i+1]-k*2
想想都明白。。轉移過程中再維護一下[i+1][k]是從**轉移過來的,說白了就是g[i+1][k]=j..
設c為c中1的個數,如果f[n][c]==1那就一定能找出一種方案,==0一定無解(其實測試點裡完全沒有。。。)
剩下的就是考慮倒推,把答案推出來了。設ans[i]為第i步運算完的答案,w[i]為第i位上的值(就是最後輸出的結果)。那麼當前知道ans[n]=c,要推出ans[n-1]和w[i]。依次類推出所有的。因為題目說只用輸出一組解,那麼怎麼方便怎麼搞就行。(實際上spj完全不能用。。。結果各種猜出題人意圖,才輸出了測試點。。。)
還是分別考慮。對了,首先要有ans[i-1],w[i],還有ans[i-1]&w[i]中1的個數,當前有a[i],g[i-1][last],還有last的,把上面的式子移一下項k就出來了。
&:ans[i]含有的1,ans[i-1]和w[i]裡都有,所以直接賦過去,然後考慮ans[i-1]和w[i]還有1沒被填上,先滿足ansi-1,找到ans[i]是0的位,賦成1,再滿足w[i],找ans[i-1],ans[i]都是0的位就好了。
|:ans[i]是ans[i-1]和w[i]的並集,所以所有的1都在ans[i]是1的位上,模擬運算過程搞。先滿足交際,再分別找各自為1的位置。
^:這個ans[i-1]和w[i]的交集的位上ans[i]都是0,而它們分別為1的位ans[i]為1.
根據這個倒推到頭,w[1]=ans[1],就好了。
博主我想揍死出題人。
#include
#include
#include
#include
#include
#define n 100005
using
namespace
std;
int read()
while(x>='0'&&x<='9')
return sum*f;
}int n,m,c,c,xp[32],a[n],opt[n],g[n][32],ans[n],w[n];
bool f[n][32];
void dfs(int x,int las)
int s=g[x][las],ax=a[x],l;
if(opt[x-1]==1)
if(opt[x-1]==2)
if(opt[x-1]==3)
dfs(x-1,g[x][las]);
}int main()
for(int i=1;i<=n;i++)a[i]=read();
f[1][a[1]]=1;
for(int i=1;ifor(int j=0;j<=m;j++)
for(int i=0;iif(xp[i]&c)c++;
if(!f[n][c])
ans[n]=c;
dfs(n,c);
}
壓縮dp的位運算
壓縮dp用到了二進位制位運算上的東西,整理一下基本內容。位運算的幾個基本操作 1 移位 2 按位與 3 按位或 4 非 5 異或 每個都很簡單,c 上都學過,難的實在那幾個巧妙的利用上。1 判斷乙個數二進位制下第i位是0或1 x 1 i 1 0 1 i 1 構造出來 100.後面i 1個0 與x做與...
狀態壓縮DP之位運算總結
介紹 在進行dp題目分析時,針對狀態或子狀態可以抽象為 0 1 排列組合的題目時,將其 0 1 序列轉化為二進位制數,再而轉換為十進位制數,可以更加便捷的對其進行資料分析處理,減少因為混亂所造成的一些不必要的錯誤。魔鬼往往藏在細節之中。常用運算子 都是十進位制數在二進位制下所做的運算,返回十進位制的...
基於DP 位運算的RMQ演算法
rmq演算法,是乙個快速求區間最值的離線演算法,預處理時間複雜度o n log n 查詢o 1 所以是乙個很快速的演算法,當然這個問題用線段樹同樣能夠解決。問題 給出n個數ai,讓你快速查詢某個區間的的最值。演算法分類 dp 位運算 演算法分析 這個演算法就是基於dp和位運算子,我們用dp i j ...