题意:
给定一个序列
s[ ],求一个p序列满足以s[i]为前p[i-1]项的和(p[i-1]项呈递减)--------举个例子
对于样例0 0 0
样例3 2 1满足是小于p[i]的前p[i-1]项和为0
题解:
树状数组+二分,或线段树+二分,树状数组的树形结构可以满足线段树的作用,所以用简单的树状数组去替代线段树即可
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define maxn 200005
ll c[maxn];
ll s[maxn];//给定序列
ll p[maxn];//得到序列
ll n;
ll lowbit(ll x)//二进制操作
{
return x&(-x);
}
ll getsum(ll i)//可以单点查询,也可以求和,根据update()
{
ll ans=0;
while(i>0)
{
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
ll update(ll i,ll k)
{
while(i<=n)
{
c[i]+=k;
i+=lowbit(i);
}
}
ll lower(ll l,ll r,ll i)
{
ll ans;
while(l<=r)
{
ll mid=(l+r)>>1;
if(getsum(mid-1)<=s[i])
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
p[i]=ans;
update(ans,-ans);
}
int main()
{
while(~scanf("%lld",&n)&&n)
{
memset(s,0,sizeof(s));
memset(p,0,sizeof(p));
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%lld",&s[i]);
update(i,i);
}
for(int i=n;i>0;i--)
{
ll l=1,r=n;
lower(l,r,i);
}
for(int i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",p[i]);
else
printf("%d\n",p[i]);
}
}
}
本文介绍了一种使用树状数组结合二分查找的算法,以解决特定类型的序列问题。通过实例讲解了如何求解一个序列,使得其前p[i-1]项的和等于给定序列s[i],且p[i-1]项呈递减趋势。代码实现清晰,适合算法学习者参考。

428

被折叠的 条评论
为什么被折叠?



