給定乙個整數 mm,對於任意乙個整數集合 ss,定義「校驗值」如下:
從集合 ss 中取出 mm 對數(即 2∗m2∗m 個數,不能重複使用集合中的數,如果 ss 中的整數不夠 mm 對,則取到不能取為止),使得「每對數的差的平方」之和最大,這個最大值就稱為集合 ss 的「校驗值」。
現在給定乙個長度為 nn 的數列 aa 以及乙個整數 tt。
我們要把 aa 分成若干段,使得每一段的「校驗值」都不超過 tt。
求最少需要分成幾段。
輸入格式
第一行輸入整數 kk,代表有 kk 組測試資料。
對於每組測試資料,第一行包含三個整數 n,m,tn,m,t 。
第二行包含 nn 個整數,表示數列a1,a2…ana1,a2…an。
輸出格式
對於每組測試資料,輸出其答案,每個答案佔一行。
資料範圍
1≤k≤121≤k≤12,
1≤n,m≤5000001≤n,m≤500000,
0≤t≤10180≤t≤1018,
0≤ai≤220
思路:首先計算的話肯定是需要每次貪心的取最大最小然後計算,但在考慮區間的時候列舉顯然是不行的,所以我們需要考慮倍增來寫,每次判斷能否擴充套件。由於取最大最小需要有序,我們每次儲存之前的左區間,然後對右區間進行排序,利用歸併的思想將有序的左右區間合成乙個有序區間,然後就可以進行判斷了。
#includeusing namespace std;
typedef long long ll;
const int maxn = 5e5 + 10;
const ll linf = 0x3f3f3f3f3f3f3f3f;
ll a[maxn], b[maxn], v[maxn];
int n, m, k;
ll t;
void merge(int l, int mid ,int r)
while(i <= mid) b[++k] = a[i++];
while(j <= r) b[++k] = a[j++];
}bool check(int l, int mid, int r) // 判斷區間是否可擴充套件
if(ret <= t)
return false;
}int main()
else if(r + len <= n && check(l, r, r + len))
else len >>= 1;
}if(r == n) ++tot;
printf("%d\n", tot);
}return 0;
}
AcWing 109 天才ACM 倍增
題目鏈結 這道題最基本的想法就是一次尋找每個區間,對於每個區間,用二分來判定其最大長度。每次check的時候,對區間排序,不斷取出不大於m對最大值與最小值求值即可。然後你就喜提tle了,笑如果用倍增來代替二分的話能過,不過其實倍增最壞複雜度和二分一樣,應該是資料沒有刻意來卡倍增。下面先給出倍增的 c...
唯一天才挽救不了AC公尺蘭沒落
在幾天前,義大利各大 還在盛讚卡卡是新一代的 球王 是本屆歐洲金球獎的有力競爭者,但緊跟著ac公尺蘭就輸球了,擁有天才球員卡卡,但不代表擁有勝利,畢竟足球是11個人的比賽,乙個卡卡,無法挽救落難的ac公尺蘭。僅僅是擁有乙個巨星的球隊是無法成功的,否則當年擁有羅納爾迪尼奧的巴黎聖日耳曼就不會一無所獲了...
SDOI2017 天才黑客
我們不妨思考一下,兩個串的 lcp 的長度在 trie 樹上是什麼?對應點的 lca 的深度。然後就可以想到把邊看成點,然後把邊與邊之間連邊,點權看成這條邊經過所需要的時間。但是這樣子連邊是 o m 2 的,不夠優秀。我們需要進一步優化。考慮兩個點之間的 lcp 可以用什麼來代替?sa 裡面的 he...