题目描述
给定长度为
N
的自然数序列
100%
数据满足
1≤n≤105
,
K≤50
,
0≤ai≤109
。
思路
其实就是个加权排列组合题。亏我当时还写个线段树维护最大值。
取第
i
大值再乘个
线段树版:
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define LL long long
const size_t MN = 100005, modn = 1000000007;
int N, K;
LL ans;
LL C[MN][55];
class Segmenttree
{
private:
#define MN (100005)
#define ls num << 1
#define rs num << 1 | 1
#define lson l, mid, ls
#define rson mid + 1, r, rs
int mx[MN << 2], tot;
void pushUp(int num)
{
mx[num] = max(mx[ls], mx[rs]);
}
void build(int l, int r, int num)
{
if (l == r)
{
scanf("%d", &mx[num]);
return ;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushUp(num);
}
int query(int L, int R, int l, int r, int num)
{
if (L <= l && r <= R)
return mx[num];
int ret = 0;
int mid = (l + r) >> 1;
if (L <= mid) ret = max(ret, query(L, R, lson));
if (R > mid) ret = max(ret, query(L, R, rson));
return ret;
}
void modify(int m, int c, int l, int r, int num)
{
if (l == r)
{
mx[num] = c;
return ;
}
int mid = (l + r) >> 1;
if (mx[ls] == m) modify(m, c, lson);
else modify(m, c, rson);
pushUp(num);
}
public:
void build() {tot = 0; build(1, N, 1);};
int query(int l, int r) {return query(l, r, 1, N, 1);}
void modify(int m, int c) {modify(m, c, 1, N, 1); }
};
Segmenttree st;
void init()
{
C[0][0] = 1;
for (int i = 1;i <= N;i ++)
{
for (int j = 1;j <= min(i, K);j ++)
{
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % modn;
//printf("C[%d][%d] = %d\n", i, j, C[i][j]);
}
}
}
int main()
{
scanf("%d%d", &N, &K);
st.build();
init();
for (int i = N;i >= K;i --)
{
int tmp = st.query(1, N);
ans = (ans + tmp * C[i][K] % modn) % modn;
//printf("tmp = %d,ans += %lld = %lld\n", tmp, tmp * C[i][K], 1 * ans);
st.modify(tmp, -1);
}
printf("%lld", ans);
return 0;
}
sort版:
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define LL long long
const size_t MN = 100005, modn = 1000000007;
LL n[MN], C[MN][55], ans;
void init(int N, int K)
{
C[0][0] = 1;
for (int i = 1;i <= N;i ++)
{
for (int j = 1;j <= min(i, K);j ++)
{
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % modn;
//printf("C[%d][%d] = %d\n", i, j, C[i][j]);
}
}
}
int main()
{
int N, K;
scanf("%d%d", &N, &K);
init(N, K);
for (int i = 1;i <= N;i ++)
{
scanf("%lld", &n[i]);
}
sort(n + 1, n + N + 1);
for (int i = N;i >= K;i --)
{
LL tmp = n[i];
ans = (ans + (tmp * C[i][K]) % modn) % modn;
}
printf("%lld", ans);
return 0;
}
最后, 众所周知地,sort跑的比线段树快不是那么一点点:代码短的不是那么一点点。