题意:n(n < 1e5)个人排成一行,把它切成若干堆,要求每一堆的长度不超过l(l < 1e5),并且每一堆的最右一个人的身高都要比前一堆的最右一个人的身高要高,对于每一种方案,它的分数是SUM(b[k]^2-b[k-1] ) b[k] 为第k堆最右一个人的身高 要求最高的分数。
注意是不能打乱顺序的
定义Dp[i]表示前i个人分成若干堆得到的最高分数,第i个人是结尾的那一个,所以很显然有状态转移:
Dp[i] = max(Dp[j] - H[j]) + H[i] ^ 2,i - l <= j <= i - 1
我写得很基础,线段树里面带了左右下标
线段树优化:
Status Accepted Time 998ms Memory 8136kB Length 2005 Lang G++ Submitted 2017-06-12 14:41:27 Shared RemoteRunId 20861352 #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> using namespace std; typedef long long LL; const int Max = 100005; const int INF = 0x3f3f3f3f; struct node{ LL h; int p; bool operator<(const node & X)const{ if(h == X.h) return p > X.p; return h < X.h; } }P[Max]; struct tree{ int l, r; LL val; }Tr[Max << 2]; int N, L; LL Dp[Max]; void getll(LL & num){ char c; int flag = 1; num = 0LL; while((c = getchar()) < '0' || c > '9') if(c == '-') flag = -1; while(c >= '0'&& c <= '9'){ num = num * 10 + c - 48; c = getchar();} num *= flag; } void getint(int & num){ char c; int flag = 1; num = 0; while((c = getchar()) < '0' || c > '9') if(c == '-') flag = -1; while(c >= '0'&& c <= '9'){ num = num * 10 + c - 48; c = getchar();} num *= flag; } void build(int i, int l, int r){ Tr[i].l = l, Tr[i].r = r; Tr[i].val = -1; if(l == r) return ; int mid = (l + r) >> 1; build(i << 1, l, mid); build(i << 1 | 1, mid + 1, r); } void insert(int i, int p, LL val){ if(Tr[i].r < p || Tr[i].l > p) return ; if(Tr[i].l == p && Tr[i].r == p){ Tr[i].val = max(Tr[i].val, val); return ; } insert(i << 1, p, val); insert(i << 1 | 1, p, val); Tr[i].val = max(Tr[i << 1].val, Tr[i << 1 | 1].val); } LL Query(int i, int l, int r){ if(Tr[i].r < l || Tr[i].l > r) return -1; if(l <= Tr[i].l && r >= Tr[i].r) return Tr[i].val; return max(Query(i << 1, l, r), Query(i << 1 | 1, l, r)); } int main(){ int T, tot = 0; getint(T); while(T --){ getint(N), getint(L); printf("Case #%d: ", ++ tot); for(int i = 1; i <= N; ++ i) getll(P[i].h), P[i].p = i; sort(P + 1, P + N + 1); build(1, 0, N); insert(1, 0, 0); for(int p = 1; p <= N; ++ p){ int i = P[p].p; LL j = Query(1, max(i - L, 0), i - 1); if(j >= 0){ Dp[i] = j + P[p].h * P[p].h; insert(1, i, Dp[i] - P[p].h); } } if(Dp[N] > 0) printf("%I64d\n", Dp[N]); else puts("No solution"); memset(Dp, -1, sizeof(Dp)); } return 0; }