Tony的口胡呼呼(。-ω-)zzz

三分

給定平面內 \(n <= 2000\) 個節點, 求平面內一點使獲得全部點的歐幾里得距離和最小
肯定 \(y\) 軸時 \(x\) 軸知足單峯函數
\(x\) 軸同理
三分套三分便可數據結構

深度優先搜索

從起始狀態少的一側開始搜索更優函數

例題

給你一副撲克中的 \(n\) 張牌, 出的下一張牌須要爲前面出牌點數之和的約數, 求一種合法的方案spa

此題正向搜索代碼以下:code

void dfs(int depth, int sum){
    if(depth == n){
        output();
        return ;
        }
    REP(i, 1, n){
    if(!vis[i] && sum % a[i] == 0){
        vis[i] = 1;
        dfs(depth + 1, sum + a[i]);
        vis[i] = 0;
        }
    }
}

顯然初始分支不少, 考慮逆向搜索遞歸

void dfs(int depth, int left){
    if(depth == 0){output();return ;}
    REP(i, 1, n){
    if(!vis[i] && (left - a[i]) % a[i] == 0){
        vis[i] = 1;
        dfs(depth - 1, left - a[i]);
        vis[i] = 0;
        }
    }
}
//調用
dfs(n, sum[a[i]]);

初始分支減小, 搜索量減小數學

meet-in-the-middle

在指數級別複雜度顯然沒法承受時, 分別從兩側開始搜索, 在中間相遇, 減小搜索量
通常分別作 \(dfs\) 後, 在左邊利用二分查找(或各類數據結構)尋找對應右邊的值, 獲得解的個數(用 \(STL\ map\) 也是很好的選擇)class

當發現有 \(\%\) 的時候大大下降搜索次數

一般下降次數的方式是搜索

  1. 減小調用量(整除才進入)
  2. 枚舉因子

數學部分

exgcd

\[gcd(a,b) = !b ? a : gcd(b, a \% b) \]
\[b == 0\] 時, 有 \[gcd(a, 0) = a\]
\[ax_{0} + by_{0} = gcd(a, b)\]
此時 \[a * 1 + 0 * 0 = gcd(a, 0) = a\] 顯然有
\[x_{0} = 1, y_{0} = 0\]
現已遞歸求得 \[bx_{0} + (a \% b)y_{0} = d\]
\[(a\%b) = a - \lfloor \frac{a}{b} \rfloor * b\]
構形成 \[ax + by = d\] 形式得
\[ay_{0} + b(x_{0} - \lfloor \frac{a}{b} \rfloor * y_{0}) = d\]
\[x = y_{0}, y = x_{0} - \lfloor \frac{a}{b} \rfloor * y_{0}\]map

Code

int exgcd(int a, int b, int &x, int &y){
    if(!b){x = 1, y = 0;return a;}
    int d = exgcd(b, a % b, x, y);
    int temp = x;x = y;y = temp - (a / b) * y;
    return d;
    }

有關於線段樹和樹剖

線段樹標記下推記得考慮對子節點標記的影響
如果多組詢問, 初始化時記得考慮以下幾個方面gc

nume = 1;//原圖邊編號
    memset(head, 0, sizeof(head));//初始化原圖
    tot = 0;//樹剖節點
    lazytag = -1;//線段樹懶標記
相關文章
相關標籤/搜索