一.尺取法
1.定義
尺取法,顧名思義,就是規定一個尺子,也就是一個限制條件,然後在一個序列中找滿足這個條件的子序列。顯然易懂,代碼也不長,純屬暴力。
2.實現方法
這和莫隊有一點相似。我們先規定一個左指針和右指針,從序列的第一個位置開始。如果當前指針內區間的值的和小於要求的和,就右指針往右移,如果當前指針內區間的值的和大於或等於要求的和,就左指針往右移。通常在左指針移動之後來統計區間最小長度。
3.模板
void FindSumK (){//s是限制條件,a數組是原序列
ans = INF;
l = r = 1;
sum = a[1];
while (r <= n){
while (sum < s && r <= n){
r ++;
sum += a[r];
}
while (sum >= s){
sum -= a[l];
l ++;
}
ans = min (ans, r - l + 2);//很明顯,左指針前面的那一個數到右指針之間的和大於或等於要求和,所以區間長度應爲r - (l - 1) + 1 = r - l + 2
}
}
很簡單吧!
二.板題
1.Subsequence
1.題目
2.題解
這裸的尺取,直接敲。
3.Code
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define M 100005
#define INF 0x3f3f3f3f
#define LL long long
int T, n, s, a[M], l, r, ans;
LL sum;
void FindSumK (){
ans = INF;
l = r = 1;
sum = a[1];
if (sum >= s){
ans = 1;
return ;
}
while (r <= n){
while (sum < s && r <= n){
r ++;
sum += a[r];
}
while (sum >= s){
sum -= a[l];
l ++;
}
ans = min (ans, r - l + 2);
}
}
int main (){
scanf ("%d", &T);
while (T --){
memset (a, 0, sizeof a);
scanf ("%d %d", &n, &s);
LL ss = 0;
for (int i = 1; i <= n; i ++){
scanf ("%d", &a[i]);
ss += a[i];
}
if (ss < s){
printf ("0\n");
continue;
}
FindSumK ();
printf ("%d\n", ans);
}
return 0;
}
2.Bound Found
1.題目
2. 題解
這道題目就沒有這麼簡單了,原序列它是不滿足單調性的。
但是要注意“絕對值”這三個字,假如我們統計了一個前綴和sum,那麼| sum[r] - sum[l] | = | sum[l] - sum[r] |
所以說,我們可以把前綴和拿來排個序,前綴和就滿足單調性,並且不管哪兩個前綴和相減,都能滿足題意,它都是一個區間。
問題就巧妙地解決了。
但是注意,不能用sum[r] - sum[l - 1]來計算區間和,因爲sum[l]和sum[l - 1]這兩個前綴和在原序列中可能沒有挨在一起!!!
所以一開始賦值l = 0,r = 1,到時候直接sum[r] - sum[l]就行了。
3.Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define M 100005
struct node {
int id, v;
}sum[M];
int n, k, ansl, ansr, a, t, ans;//別用long long,我用都錯了
int fabs (int x){
return x < 0 ? -x : x;
}
bool cmp (node a, node b){
return a.v < b.v;
}
void FindSumK (int order){
int l = 0, r = 1, minn = 0x3f3f3f3f;
while (minn && r <= n){
int ss = sum[r].v - sum[l].v;
if (fabs (ss - order) < minn){
minn = fabs (ss - order);
ans = ss;
ansl = min (sum[l].id, sum[r].id);
ansr = max (sum[l].id, sum[r].id);
ansl ++;
}
if (ss < order)
r ++;
if (ss > order)
l ++;
if (r == l)
r ++;
}
}
int main (){
while (scanf ("%d %d", &n, &k)){
memset (sum, 0, sizeof sum);
if (! n && ! k)
break;
for (int i = 1; i <= n; i ++){
scanf ("%d", &a);
sum[i].v = sum[i - 1].v + a;
sum[i].id = i;
}
sort (sum, sum + 1 + n, cmp);
while (k --){
scanf ("%d", &t);
FindSumK (t);
printf ("%d %d %d\n", ans, ansl, ansr);
}
}
return 0;
}