题目:![](https://img-blog.csdnimg.cn/df267a8e029741edbd11892051c37146.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAYl8xOV8yMF8yMQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
输入:
思路:
一开始使用二分然后简单剪枝,但其实问题会出在N上,只能拿到70分
看了学长的代码学习之后
这里由于N是1e9,就算是O(N)的时间复杂度也会超出限制,因此必须要分段处理。
对于g来说,每r个元素就是一段
对于f来说,输入的数组的两个元素之间就是一段
因此查找g和f共存的那些部分,进行合并求和即可
代码:
#include<bits/stdc++.h>
using namespace std;
long long n=0,N=0;
int main()
{
cin>>n>>N;
long long res=0;
long long r=N/(n+1);
vector<long long>d(n+1,0);
for(int i=1;i<=n;i++)
{
cin>>d[i];
}
vector<pair<long long,long long> >f;
for(int i=1;i<=n;i++)
{
f.push_back({d[i-1],d[i]-1});//f的每一段就是两个元素之间的部分,左闭右开
}
f.push_back({d[n],N-1});
int p=0;
for(long long i=0;i<N;i+=r)
{
long long fl=f[p].first;
long long fr=f[p].second;
long long gl=i;
long long gr=min(i+r-1,N-1);//这里需要注意,最后可能+r会超出N-1,要限制一下
long long L=max(fl,gl);
long long R=min(fr,gr);
res+=(R-L+1)*abs(p-i/r);//对于共有的段归并一起求和
if(R==fr)//如果一个f段到边界
{
p++;
}
if(R!=gr)//如果没有到g段的边界,下次仍然要用这个g段
{
i-=r;
}
}
cout<<res<<endl;
system("pause");
return 0;
}