K 小馬哥的超級鹽水 分治 暴力

2021-08-18 09:16:17 字數 1521 閱讀 6374

時間限制:c/c++ 5秒,其他語言10秒

空間限制:c/c++ 131072k,其他語言262144k

64bit io format: %lld

小馬哥有

輸入第一行包含乙個整數每組資料第一行包含三個整數

接下來

每組資料輸出一行,包含乙個整數表示非空子集的個數。
示例1

1

5 1 2

1 21 2

1 21 2

1 4

15
2^35次方暴力肯定超時,但是用用分治,將問題1分為2,那麼2^17和2^18次方這就不會超時了,題目給了5s。對分成的兩部分進行dfs,對於一瓶鹽水,都有拿和不拿兩個狀態,dfs正常思路就可以了 。比較麻煩的是,如何處理x/y的問題,其實這個問題就是將一棵樹,分為兩顆子樹i,j,先對i進行操作,滿足ai/bi==x/y 即 ai*y-bi*x==0,這就是滿足條件的,而且不滿足條件的ai*y-bi*x也要記錄下來,因為減法肯定有正有負,因此我們不能用陣列,要用map(對映) ,先把所有i樹的所有條件都記錄下來,那麼接下來對j樹的處理就是關鍵了。————大佬教我的!!!

首先我們先看,j樹直接符合x/y的,假如說i樹有n種,j樹有m種,那麼單純符合x/y的組合就有n*m種,但是我們條件不能直接相乘,我們應該用加例如說,對於i樹 ,f[0]=3,我們找到乙個符合的值那麼我們應該用sum+=f[0],如果在找到乙個,那麼繼續sum+=f[0]。

接著,我們看如果兩瓶鹽水單獨不符合,但是混合後符合的情況,i樹元素和j樹元素如果(ai+aj)/(bi+bj)==x/y 那麼我們就有ai*y-bi*x==-aj*y+bj*x ,因此只要滿足這個條件我們就可以混合起來,算一種了。也就是說,當求出j樹的乙個元素為-aj*y+bj*x, 那麼f[-aj*y+bj*x]就是找到它對應在i樹里混合後等於x/y的值,也就是f[ai*y-bi*x],那麼直接sum+=f[-aj*y+bj*x]就可以得到它們總共混合後的種類數,其實也就是相當於上面的n*m。因此j樹的邊界操作應該是sum+=f[-aj*y+bj*x].

最後一點就是,我們這樣做在第i樹集合裡面我們會有一種情況就是所有水都不取,j樹也一樣,那麼這就是空集了,因此我們算出來的總個數還要-1才是所求的

#include #include #include #include #include #define ll long long

using namespace std;

mapf;

int n,m,x,y;

ll a[40],b[40],sum;

void dfs(ll v1,ll v2,int step)

dfs(v1+a[step],v2+b[step],step+1);

dfs(v1,v2,step+1);

}void dfs(ll v1,ll v2,int step)

dfs(v1+a[step],v2+b[step],step+1);

dfs(v1,v2,step+1);

}int main()

}

小馬哥的超級鹽水

來呀 題意 給n杯鹽水,每一杯水有a單位鹽,b單位水。給你乙個x和y,問有多少種方法能配成x比y的鹽水。因為n只有35,沒法列舉全部情況,如果n只有一般大,那麼我們可以列舉所有情況。我們可以把n分為兩部分,列舉一部分的所有情況,然後找是否能和另一部分構成解。對於 a1,b1 和 a2,b2 這兩個集...

牛客網 小馬哥的超級鹽水 (雙向列舉)

分析 n的最大值能達到35,有2 35種狀態,不能直接列舉所有的狀態。但可以把n分成兩個部分,這樣每個部分的狀態列舉就能在規定時間內達到。設i為第乙個部分的狀態,j為第二個部分的狀態。則有 ai aj bi bj x y,進一步化為 ai y bi x bj x aj y 就可以在將每個第一部分的狀...

18華工校賽 小馬哥的超級鹽水 折半列舉

小馬哥有 n 杯鹽水,第 i 杯有 a i 單位的鹽和 b i 單位的水。小馬哥很無聊,於是他想知道有多少種這 n 杯鹽水的非空子集,倒在一起之後鹽和水的比是 frac 範圍 2 這道題比賽沒a出來,要是a了就能兩個人分900塊辣 隔了一天才突然想到,我太菜了 折半列舉過程如下 分兩個桶a,b,分別...