Description
Y sera 陷入了沉睡,幻境中它梦到一个长度为N 的序列{Ai}。
对于这个序列的每一个子串,定义其幻境值为这个子串的和,现在Y sera 希望选择K 个不同的子串并使得这K 个子串的幻境值之和最大。
然而由于梦境中的种种限制,这些子串的长度必须在L 到R 之间。
你需要告诉她,最大的幻境值之和。
Solution
先对
Ai
做前缀和
Si
,然后对于一个
i
作为结尾,一个合法的
还有一种与
K
无关的算法,同样考虑前缀和,首先二分一个
Solution
与 K <script type="math/tex" id="MathJax-Element-2118">K</script>无关的算法,跑得真慢。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100010
#define _ 1000000000
#define ll long long
using namespace std;
struct node{
ll s;
int x,l,r;
}tr[N*55];
ll s[N];
void update(int v){
tr[v].s=tr[tr[v].l].s+tr[tr[v].r].s;
tr[v].x=tr[tr[v].l].x+tr[tr[v].r].x;
}
int rt[N],tot=0;
void insert(int &v,int l,int r,int x){
tr[++tot]=tr[v],v=tot;
if(l==r){
tr[v].s+=x,tr[v].x++;
return;
}
int mid=((ll)l+r)/2;
if(x<=mid) insert(tr[v].l,l,mid,x);
else insert(tr[v].r,mid+1,r,x);
update(v);
}
ll findsum(int v0,int v1,int l,int r,int x,int y){
if(l==x && r==y){
return tr[v0].s-tr[v1].s;
}
int mid=((ll)l+r)/2;
if(y<=mid) return findsum(tr[v0].l,tr[v1].l,l,mid,x,y);
else if(x>mid) return findsum(tr[v0].r,tr[v1].r,mid+1,r,x,y);
else return findsum(tr[v0].l,tr[v1].l,l,mid,x,mid)+findsum(tr[v0].r,tr[v1].r,mid+1,r,mid+1,y);
}
int find(int v0,int v1,int l,int r,int x,int y){
if(l==x && r==y){
return tr[v0].x-tr[v1].x;
}
int mid=((ll)l+r)/2;
if(y<=mid) return find(tr[v0].l,tr[v1].l,l,mid,x,y);
else if(x>mid) return find(tr[v0].r,tr[v1].r,mid+1,r,x,y);
else return find(tr[v0].l,tr[v1].l,l,mid,x,mid)+find(tr[v0].r,tr[v1].r,mid+1,r,mid+1,y);
}
int n,K,L,R;
bool check(int x){
int cn=0;
fo(i,1,n-L+1)
{
int l=i+L-2,r=min(i+R-1,n);
if((ll)s[i-1]+x<=_*2) cn+=find(rt[r],rt[l],0,_*2,s[i-1]+x,_*2);
}
return cn>=K;
}
int main()
{
freopen("fantasy.in","r",stdin);
freopen("fantasy.out","w",stdout);
scanf("%d %d %d %d",&n,&K,&L,&R);
fo(i,1,n)
{
int x;
scanf("%d",&x);
s[i]=s[i-1]+x;
rt[i]=rt[i-1],insert(rt[i],0,_*2,s[i]+_);
}
int l=0,r=_*2;
while(l+1<r){
int mid=((ll)l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
if(check(r)) l=r;
int cn=0;
ll ans=0;
fo(i,1,n-L+1)
{
int p=i+L-2,q=min(i+R-1,n);
int tmp=find(rt[q],rt[p],0,_*2,s[i-1]+l,_*2);
cn+=tmp;
ans+=findsum(rt[q],rt[p],0,_*2,s[i-1]+l,_*2)-(s[i-1]+_)*tmp;
}
if(cn>K) ans=ans-(cn-K)*(l-_);
printf("%lld",ans);
}