hihoCoder挑戰賽31
#1595 : Numbers
時間限制:8000ms 單點時限:1000ms 內存限制:256MB描述
給定n個整數常數c[1], c[2], ..., c[n]和一個整數k。現在需要給2k個整數變量x[1], x[2], ..., x[k], y[1], y[2], ..., y[k]賦值,滿足
(1)對於所有1 ≤ i ≤ k,都有x[i] ≤ y[i]。
(2)對於所有1 ≤ i ≤ n,都存在至少一個j (1 ≤ j ≤ k),使得x[j] ≤ c[i] ≤ y[j]。
求出S=(y[1] + y[2] + ... + y[k]) - (x[1] + x[2] + ... + x[k])的最小值。
輸入
第一行兩個整數n, k。(1 ≤ n, k ≤ 100000)
接下來n行,每行一個整數c[i]。 (-1000000000 ≤ c[i] ≤ 1000000000)
輸出
輸出一個整數表示S的最小值。
樣例解釋
x[1]=-5, y[1]=4,
x[2]=10, y[2]=10.
- 樣例輸入
-
5 2 -5 0 10 4 0
- 樣例輸出
-
9
首先,如果k≥n則可以零距離夾住每個c,此時答案為0。
當k<n時,只需將n個數字從小到大排序,去掉其中最長的k-1個間隔即可。
#include<stdio.h> #include<stringView Code.h> #include<stdlib.h> long long c[100005], d[100005]; int cmp(const void * x, const void * y) { return *((long long *) x) > *((long long *) y); } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif int n, k; scanf("%d%d", &n, &k); for(int i = 0; i < n; i++) { scanf("%lld", &c[i]); } if (k >= n) { printf("0\n"); return 0; } qsort(c, n, sizeof(long long), cmp); for (int i = 0; i < n - 1; i++) { d[i] = c[i + 1] - c[i]; } qsort(d, n - 1, sizeof(long long), cmp); long long ans = c[n - 1] - c[0]; for (int i = 1, j = n - 2; i < k; i++, j--) { ans -= d[j]; } printf("%lld\n", ans); return 0; }
#1596 : Beautiful Sequence
時間限制:11000ms 單點時限:1000ms 內存限制:256MB描述
對於一個正整數列a[1], ... , a[n] (n ≥ 3),如果對於所有2 ≤ i ≤ n - 1,都有a[i-1] + a[i+1] ≥ 2 × a[i],則稱這個數列是美麗的。
現在有一個正整數列b[1], ..., b[n],請計算:將b數列均勻隨機打亂之後,得到的數列是美麗的概率P。
你只需要輸出(P × (n!))mod 1000000007即可。(顯然P × (n!)一定是個整數)
輸入
第一行一個整數n。 (3 ≤ n ≤ 60)
接下來n行,每行一個整數b[i]。 (1 ≤ b[i] ≤ 1000000000)
輸出
輸出(P × (n!))mod 1000000007。
- 樣例輸入
-
4 1 2 1 3
- 樣例輸出
-
8
滿足美麗性質的序列形狀為V字形,即先遞減後遞增,單調序列可以理解為左邊或右邊長度為0的V字形。
V字形最低點的數字一定是數列中最小的數字,把數列按從小到大的順序依次添加到兩端,只要保證每次添加時和該端最邊上的兩個數字滿足美麗性質,即可實現美麗數列的構造。
首先按從小到大的順序排序
令dp[i][j][k][l]為當前的數列最左邊的兩個的下標分別為ij,最右邊的兩個數字的下標分別為kl時的美麗數列個數。若i=j,表示右邊沒有了;若k=l,表示左邊沒有了。
可以通過一個四重循環ijkl實現狀態轉移,第一重表示當前要添加下標為i的數字,顯然,此時數列最左端或最右端的數字中一定有一個編號為i-1,用三重循環jkl枚舉另外三個數字。i-1在左邊或右邊分兩種情況,每種情況下各自可能將i添加到左邊或右邊,一共四次判斷,復雜度為O(n^4)。
再想一想的話,其實在循環i時,兩端的四個數字裏除了必定有一個i-1之外,i-2肯定也在其中,所以其實只用枚舉另外兩個數字就行了,這種情況下要寫八次判斷,復雜度為O(n^3),應該也是可以的,不過沒有試。
#include<stdio.h> #include<string.h> #include<stdlib.h> int n; long long dp[65][65][65][65], a[130]; int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lld", &a[i]); } for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { if (a[i] > a[j]) { long long t = a[i]; a[i] = a[j]; a[j] = t; } } } int cnt = 0; for (int i = 0; i < n; i++) { if (a[i] == a[0]) { cnt++; } } for (int i = 1; i < n; i++) { a[i] = a[i + cnt - 1]; } n = n - cnt + 1; memset(dp, 0, sizeof(dp)); dp[0][0][0][0] = dp[0][1][0][1] = dp[1][0][1][0] = 1; for (int i = 2; i < n; i++) { for (int j = 0; j < i; j++) { for (int k = 0; k < i; k++) { for (int l = 0; l < i; l++) { //dp[i-1,j,k,l] if (i - 1 != j && k != l) { if ((long long)(a[i] + a[j]) >= (long long)(2 * a[i - 1])) { dp[i][i - 1][k][l] += dp[i - 1][j][k][l]; dp[i][i - 1][k][l] %= 1000000007; } if ((long long)(a[k] + a[i]) >= (long long)(2 * a[l])) { dp[i - 1][j][l][i] += dp[i - 1][j][k][l]; dp[i - 1][j][l][i] %= 1000000007; } } //dp[j,k,l,i-1] if (j != k && l != i - 1) { if ((long long)(a[i] + a[k]) >= (long long)(2 * a[j])) { dp[i][j][l][i - 1] += dp[j][k][l][i - 1]; dp[i][j][l][i - 1] %= 1000000007; } if ((long long)(a[l] + a[i]) >= (long long)(2 * a[i - 1])) { dp[j][k][i - 1][i] += dp[j][k][l][i - 1]; dp[j][k][i - 1][i] %= 1000000007; } } } } } } long long ans = 0; if (n > 1) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { ans += dp[n - 1][i][j][k]; ans += dp[i][j][k][n - 1]; ans %= 1000000007; } } } } else { ans = 1; } for (int i = 1; i <= cnt; i++) { ans = (ans * i) % 1000000007; } printf("%lld\n", ans); return 0; }View Code
hihoCoder挑戰賽31