尺取法:顧名思義,像尺子一樣取一段,借用挑戰書上面的話說,尺取法通常是對陣列儲存一對下標,即所選取的區間的左右端點,然後根據實際情況不斷地推進區間左右端點以得出答案。
之所以需要掌握這個技巧,是因為尺取法比直接暴力列舉區間效率高很多,尤其是資料量大的時候,所以尺取法是一種高效的列舉區間的方法,一般用於求取有一定限制的區間個數或最短的區間等等。
當然任何技巧都存在其不足的地方,有些情況下尺取法不可行,無法得出正確答案。
使用尺取法時應清楚以下四點:
1、 什麼情況下能使用尺取法?
2、何時推進區間的端點?
3、如何推進區間的端點?
4、何時結束區間的列舉?
尺取法通常適用於選取區間有一定規律,或者說所選取的區間有一定的變化趨勢的情況,通俗地說,在對所選取區間進行判斷之後,我們可以明確如何進一步有方向地推進區間端點以求解滿足條件的區間,如果已經判斷了目前所選取的區間,但卻無法確定所要求解的區間如何進一步
得到根據其端點得到,那麼尺取法便是不可行的。首先,明確題目所需要求解的量之後,區間左右端點一般從最整個陣列的起點開始,之後判斷區間是否符合條件在根據實際情況變化區間的端點求解答案。
以下是幾個經典的使用尺取法的例題,都是從挑戰書上引用的。(尺取法通常會需要對某些量進行預處理,以便能在使用時快速地判斷。)
1、 poj 3061
題意:給定乙個序列,使得其和大於或等於s,求最短的子串行長度。
分析:首先,序列都是正數,如果乙個區間其和大於等於s了,那麼不需要在向後推進右端點了,因為其和也肯定大於等於s但長度更長,所以,當區間和小於s時右端點向右移動,和大於等於s時,左端點向右移動以進一步找到最短的區間,如果右端點移動到區間末尾其和還不大於等於s,結束區間的列舉。
這個題目區間和明顯是有趨勢的:單調製化,所以根據題目要求很容易求解,但是在使用之間需要對區間字首和進行預處理計算。
**:
#include #include #include #define max 100005#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
ll a[100010];
int n, t, ans = inf;
ll sum, s;
int main()
int main()
sort(sum, sum+1+n);
while (k--)
if(b > t) st++;
else if(b < t) en++;
else break;
if(st == en) en++;
}if (u < l) swap(u, l);
printf("%i64d %d %d\n", ans, l+1, u);}}
return 0;
}
方法二:
// #include#include #include #include #include #include //priority_queue#include #include //multiset set>大到小
#include // vector().swap(v);清空釋放記憶體
#include #include // auto &name : stlname name.
#include #include #include //__builtin_popcount(ans);//獲取某個數二進位制位1的個數
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define read_a_int(x) scanf("%d",&x)
#define read(x,y) scanf("%d%d",&x,&y)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod1e9 = 1000000007;
const int mod998 = 998244353;
const int mod = mod1e9;
const int max_n = 1000000 + 10;
// int read()
// // while(ch>='0'&&ch<='9')
// return x*f;
// }
int n,k,t;
pairsum[max_n];
void init()
sort(sum,sum+n+1);
}void solve()
if(deltat) l++;
if(l==r) r++;
} if(ansl>ansr)
swap(ansl,ansr);
printf("%d %d %d\n",ans,ansl+1,ansr);
}int main(void)
return 0;
}
4、 poj 2739 & poj 2100
題意:找到某乙個區間使得區間內的數的和/平方和等於某一給定值k。
分析:很明顯了,幾乎之與上面的poj2566又是一樣的,當區間右端點不能再向右推進且區間和仍小於k的話就可以結束區間的列舉了。
**:
poj2739:
#include #include #include #include #include #include #define inf 0x3f3f3f3f#define ll long long
using namespace std;
int prime = ;
int main()
}printf("%d\n", ans);
}}
poj2100:
#include #include #include #include #include #include #define inf 0x3f3f3f3f#define ll long long
using namespace std;
typedef pair> p;
p ans[1010];
int main()
}printf("%d\n", k);
for (int i = 0; i < k; i++)
}return 0;
}
總結:尺取法的模型便是這樣:根據區間的特徵交替推進左右端點求解問題,其高效的原因在於避免了大量的無效列舉,其區間列舉都是根據區間特徵有方向的列舉,如果胡亂使用尺取法的話會使得列舉量減少,因而很大可能會錯誤,所以關鍵的一步是進行問題的分析!
python解題技巧 Python 解題技巧
python 解題技巧 一直都是用 c 和 c 解題,某題簡單解完後便心血來潮想用 python 解一次,發現一些問題,特寫此篇隨筆來記錄.一,輸入格式 例 輸入第 1 行給出正整數 n 和整數 m 第 2 行給出 n 個整數,其間以空格分隔.大多數題目都是要求一行給多個元素,其間以空格為間隔,而在...
Python解題技巧
python解題技巧 一直都是用c 和c解題,某題簡單解完後便心血來潮想用python解一次,發現一些問題,特寫此篇隨筆來記錄。例 輸入第1行給出正整數n和整數m 第2行給出n個整數,其間以空格分隔。大多數題目都是要求一行給多個元素,其間以空格為間隔,而在python中只用input 是不行的,若多...
常用技巧之 尺取法 理解 例題
尺取法的複雜度為 o n 主要應用有關連續性的問題,基本原理就是反覆地推進區間的開頭和末尾,來求取滿足條件的最小區間,或者相似的應用。尺取法在別的地方又被稱為滑動視窗或者蠕蟲演算法,我覺得蠕蟲演算法這個名稱用的相當恰當啊,就是一步一步地往後移動,一直找到答案,而不用遍歷回溯什麼的,也就是因為這樣,他...