首先对玉枝进行排序。枚举最大值 i ,从 i−1 开始枚举次大值 j ,枚举第三大值 k。可以发现,k 是单调递增的。这样,如果确定了一个最小的大于 wi−wj 的玉枝 k,那么当前的贡献就是 (∑i=1j−kCj−ki×i)×wi。
最后累加总和就可以了。复杂度 O(n2) 。但是每个子任务都没几个对的。求大佬解惑。
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define int long long
using namespace std;
using LL = long long;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
const int mod = 20060723;
const int N = 5010;
int n;
int c[N][N], s[N];
int w[N];
void init() {
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= i; j ++ )
c[i][j] = c[i][j] * (j + 2) % mod;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= i; j ++ )
s[i] = (s[i] + c[i][j]) % mod;
}
LL solve() {
LL ans = 0;
for (int i = 3; i <= n; i ++ ) { // ö¾Ù×î´óÖµ
int k = 1; // µÚÈý´óÖµ£¬µ¥µ÷µÝÔö
for (int j = i - 1; w[j] > (w[i] >> 1); j -- ) { // ö¾Ù´Î´óÖµ
while (w[k] + w[j] <= w[i]) k ++ ;
if (k >= j) break;
ans = (ans + s[j - k] * w[i] % mod) % mod;
}
}
return ans;
}
signed main() {
scanf("%lld", &n);
for (int i = 1; i <= n; i ++ ) {
scanf("%lld", &w[i]);
}
sort(w + 1, w + n + 1);
init();
printf("%lld\n", solve());
return 0;
}