時間限制:c/c++ 5秒,其他語言10秒
空間限制:c/c++ 131072k,其他語言262144k
64bit io format: %lld
小馬哥有
輸入第一行包含乙個整數每組資料第一行包含三個整數接下來
每組資料輸出一行,包含乙個整數表示非空子集的個數。示例1
15 1 2
1 21 2
1 21 2
1 4
152^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,分別...