折半列舉 Hash(HDU1496公升級版)

2022-06-06 03:09:09 字數 2063 閱讀 3417

給定乙個四元二次方程:

$ax1^2+bx2^2+cx3^2+dx4^2=0$ 

試求$−1000≤x1,x2,x3,x4≤1000$非零整數解的個數。

$−10000≤a,b,c,d≤10000$

輸出解的個數。

解法:

首先這道題直接用網上hdu1496的板子過不去,原因是1e10的陣列開不了那麼大的。所以這裡只能換思路。新思路如下(很典型的折半列舉,也就是meet-in-middle):

把x1,x2的答案存下來(存在乙個2000*2000的陣列裡面),然後排序

二分查詢這個陣列裡面有多個數x了

$ax_1^2+bx_2^2=-(cx_3^2+dx_4^2)$

左邊式子的答案我們已經存下來了,接下來算右邊的

右邊答案算出來過後,我們直接在左邊陣列裡面二分有多少個一樣的數值,答案加上這個數值就ok了

當然這裡用陣列會稍顯笨拙,可以用map,卡時間可以過。

注意s[a*i*i + b*j*j]++會爆int,因此需要將a改為long long

**如下:

1 #include2 #include3 #include4

using

namespace

std;

5 typedef long

long

ll;6 maps;78

intmain()

15for (ll i = 1; i <= 1000; i++) 20}

21 ll sum = 0;22

for (ll i = 1; i <= 1000; i++) 28}

29 printf("

%lld\n

", 16*sum);30}

31return0;

32 }

上面說了卡常數不是很嚴的做法,如果卡常數很嚴的話,比如x的範圍變到4000,map就會t掉,這裡直接採用hash的方法

例題:uva1152:4 values whose sum is 0

1

//hash數字編碼

2 #include3 #include4 #include5 #include6 #include7

using

namespace

std;

8 typedef long

long

ll;9 maps;

10int a[4005], b[4005], c[4005], d[4005

];11

intn, t, cnt;

1213

//w[i]表示第i個結點儲存的數(也就是a+b),st[i]表示第i個結點有多少種表示方法

14const

int hashsize = 1000003;15

int hd[hashsize], nxt[16000005], w[16000005], st[16000005

]; 16

void

in(int

x) 23 u =nxt[u];24}

25 nxt[++cnt] =hd[h];

26 hd[h] =cnt;

27 w[cnt] =x;

28 st[cnt] = 1;29

}3031int srch(int

x) 38

return0;

39}4041

intmain()

50for (ll i = 0; i < n; i++) 54}

55 ll sum = 0;56

for (int i = 0; i < n; i++) 60}

61 printf("

%lld\n

", sum);

62if (t) printf("\n"

);63}64

return0;

65 }

折半列舉0 5

0.5table of contents 折半列舉 常見型別 具體題目 poj2785 poj3977 noip2014模擬賽 某種密碼 password include include include include include include define l long long defin...

折半列舉(雙向搜尋)

各有n個整數的四個數列a b c d。要從每個數列中各取乙個數,使四個數的和為0。求出這樣組合的個數。輸入n 6 a b c d 從4個數列中選擇共有n4種情況,全部判斷一遍不可行。不過將它們對半分成ab和cd再考慮,就可以快速解決了。從2個數列中選擇的話只有n2種組合,所以可以進行列舉。先從a b...

問題 A 賭徒 折半列舉查詢

題目描述 有n個賭徒打算賭一局。規則是 每人下乙個賭注,賭注為非負整數,且任意兩個賭注都不相同。勝者為賭注恰好是其餘任意三個人的賭注之和的那個人。如果有多個勝者,我們取賭注最大的那個為最終勝者。例如,a,b,c,d,e分別下賭注為2 3 5 7 12,最終勝者是e,因為12 2 3 7。輸入輸入包含...