1. 程式人生 > 實用技巧 >8.8集訓

8.8集訓

上午

考試

下午

講圖論,改題

第一題

給定一個長度為\(n\)的序列,求這個序列所有長度為\(k\)的子序列的最大值之和,答案對\(1e9+7\)取模

顯然,觀察題面發現是“子序列”,也就是可以不連續

所以我們首先排序,然後考慮\(a[i]\)對於答案造成的貢獻,發現以\(a[i]\)為最大值的序列,\(i-1\)之前的東東他都可以造成貢獻,變相的說,是在前\(i-1\)個數裡面,選\(k-1\)個,然後這麼多次方案,\(a[i]\)對於每個方案都有貢獻,

於是答案呼之欲出啊:\(Ans = \sum_\limits {i = k} ^nC_{i-1}^{k-1}\times a[i]\),可惜在考場上沒想出來,一直在想資料結構單調棧之類的去維護他,最後沒辦法,打了二十分暴力走人

#include <bits/stdc++.h>
#define LL long long
#define debug
using namespace std;

const int N = 1e5+66, mod = 1e9+7;

int n, k;
int a[N];
LL c[N][66], res;

inline int thestars() {
	cin >> n >> k;
	for (int i = 1; i <= n; ++ i) scanf ("%d", &a[i]);
	sort (a + 1, a + n + 1);
	for (int i = 0; i <= n; ++ i) c[i][0] = 1;
	for (int i = 1; i <= n; ++ i) {
		for (int j = 1; j < k; ++ j) {
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1])%mod;
		}
	}
	for (int i = k; i <= n; ++ i) res = (res + c[i - 1][k - 1]*a[i])%mod;
	cout << res;
	return 0;
}

int youngore = thestars();

signed main() {;}

第二題

題目大意:在一個有\(n\)個站點的路上,對於\(1\leq i < n\),站點\(i\)可以一票到達站點\(i+1,i+2, i+3......Min(i+a_i, n)\)

求任意兩點\(i,j\)\(i\text~j\)的最少票數和,即求\(\sum_\limits{i=1}^{n-1}\sum_\limits{j=i}^{n} p(i,j)\)其中\(p(i,j)\)表示\(i\text~j\)的最少票數

狀態:設\(f[i]\)表示\(\sum_\limits{j = i+1}^np(i,j)\),即\(i\text~j\)的最少票數和,

轉移:

  • 對於\((i,i+a_i\rbrack\)
    ,我們可以一票賣完,轉移方程
  • 對於\((i+a_i,n\rbrack\),選擇一個合適的\(j\)作為跳板,跳到終點,顯然選擇一個\({j+a[j]}_{max}\)是最合適不過的了
  • 故當\(i+a_i=n\)時,\(f[i] = n-i\),表示\(i+1 \text~n\)都可以一票走
  • 而當\(i+a_i<n\)時,用樹狀陣列或線段樹查詢\((i,i+a_i \rbrack\)中,\(j+a_i\)最大的\(j\)
  • 轉移呼之欲出:\(f[i] = a_i+f[j]-(a_i -j)+(n-a_i)\)

結果:\(Ans = \sum_\limits{i=1}^{n-1}f[i]\)

給出AC程式碼:

#include <bits/stdc++.h>
#define lowbit(x) (x&-x)
#define LL long long
#define debug
using namespace std;

const int N = 1e5+66;

int n, a[N], mp[N], t;
LL f[N], res;

inline void chenge(int x) {
	for (int i = x; i <= n; i += lowbit(i)) {
		if (a[mp[i]] < a[x]) {
			mp[i] = x;
		}
	}
}

inline int ask(int x) {
	int yhm(0);
	for (int i = x; i; i -= lowbit(i)) {
		if (a[yhm] < a[mp[i]]) {
			yhm = mp[i];
		}
	}
	return yhm;
}

inline int thestars() {
	scanf ("%d", &n);
	for (int i = 1; i <= n-1; ++ i) {
		scanf ("%d", &a[i]);
		a[i] = min (a[i]+i, n);
	}
	for (int i = n-1; i; -- i) {
		f[i] = a[i] - i;
		if (a[i] < n) t = ask(a[i]), f[i] += f[t] - (a[i] - t) + (n - a[i]);
		chenge(i);
	}
	for (int i = 1; i <= n; ++ i) res += f[i];
	cout << res;
	return 0;
}

int youngore = thestars();

signed main() {;}