http://118.190.20.162/view.page?gpid=T137
思路很简单,细节调整很麻烦。
一看数据量,1s肯定复杂度是1e5,要么遍历g(i),要么遍历f(i),让一个去适应另一个。
首先看遍历g(i),让f(i)去适应的情况。
如果遍历g(i),给定一个g(i)的值,会对应一个i的区间,我们要算出区间的首尾的i,记为posl,posr。g(posl)==g(posr),而我们要算出f(posl)和f(posr),此处需要二分查找一下,因此不方便。显然f(posl)<f(posr)。如果f(posr)<=g(posl),说明整个区间内f(i)均小于g(i)。反之如果f(posl)>=g(posl),说明整个区间内f(i)均大于g(i)。这样只需对f(i)和g(i)分别区间求和,然后做差,求绝对值即可。区间求和用前缀和即可。但是由于f(i)的前缀和较为难求,因此我最终采用的是遍历f(i)让g(i)去适应的方式,因为g(i)规律性强更容易求前缀和。还有一种情况是f(posl)<g(posl)<f(posr),由于两个函数均为增函数,因此出现相交的概率较低,直接暴力求出区间内每一个abs(f(i)-g(i))即可。
因为给定i求f(i)和f(i)的前缀和都不太方便,因此我采取了第二种思路。总体和上述思路相同。但是如果是遍历f(i),则区间内任意i的值都是f(i),通过i来求g(i)和g(i)的前缀和都很方便,因为g(i)规律性强,类似于等差数列。
所以最终的思路为:
遍历f(i),让g(i)去适应。遍历f的每一个函数值,而每一个函数值都对应一个区间[posl,posr],在区间内当然每一个f(i)都相等,即f(posl)==f(i)==f(posr)。之后要对f(i)和g(i)分别区间求和,分为两种情况,第一种是f(i)函数值均大于g(i)函数值,或者g(i)函数值均大于f(i)函数值。因为g(posl)<=g(posr),所以只需判断g函数两个端点即可。如果g(posr)<=f(i),则g函数全部小于f,如果g(posl)>=f(i),则g函数全部大于f。这两种情况只需分别区间求和然后取绝对值即可。还有一种情况为g(posl)<f(i)<g(posr),这种情况较为少见,直接暴力求出,即对每一个i求|f(i)-g(i)|。
求g函数前缀和只需要处理一下边界,然后直接等差数列求和然后再乘r即可。
注意点:
1.f函数开始默认为0 ,因此需要数组先补0.
2.f函数最后一位需要补N,处理边界问题。
3.全开long long,当时因为没看见一个地方爆longlong调了好久,还不如直接全开long long。
4.前缀和如果下标小于0的是0
#include <bits/stdc++.h>
typedef long long ll;
const ll maxn=100000;
using namespace std;
ll n,N,r;
ll a[maxn+10];
inline ll g(ll pos){
return pos/r;
}
inline ll sumg(ll pos){
if(pos<0)return 0;
else if((pos+1)%r==0)return (pos/r+1)*(pos/r)/2*r;
else return (pos/r+1)*(pos/r)/2*r-(r-(pos+1)%r)*g(pos);
}
int main()
{
cin>>n>>N;
r=N/(n+1);
a[0]=0;
for(ll i=1;i<=n;i++){
scanf("%d",&a[i]);
}
a[n+1]=N;
ll sum=0;
for(ll i=0;i<=n;i++){
ll lpos=a[i],rpos=a[i+1]-1;
ll gl=g(lpos),gr=g(rpos);
//printf("pos:(%d ,%d)\n",lpos,rpos);
ll fl=i;
if(fl<=gl||fl>=gr){
ll tsumg=ll(sumg(rpos)-sumg(lpos-1));
//printf("(sumgr,sumgl)%lld %lld\n",sumg(rpos),sumg(lpos-1));
ll tsumf=ll(fl*(rpos-lpos+1));
ll tsum=tsumg-tsumf;
sum+=llabs(tsum);
//printf("(%lld,%lld):%lld\n",tsumf,tsumg,tsum);
}
else{
ll tsum=0;
for(ll j=lpos;j<=rpos;j++){
tsum+=llabs(g(j)-fl);
}
sum+=tsum;
//printf("*%lld*\n",tsum);
}
//printf("sum:%lld\n",sum);
}
printf("%lld\n",sum);
return 0;
}