非常棒的一道题 看了就觉得是三分 三分第一个给第二个多少 其他的可以推出来 而时间上应该没问题 但是范围会出问题 如果是把范围订为定为 long long 的范围 中间的结果会超 订小了又可以覆盖不到正确答案 所以不知道范围应该订多少 用java或大数应该就能过 还有一个问题是我不能确定3分一定是对的 即它是否是一定是抛物线 所以就开始当数学题做来手推 发现设第一个给第二个x个 刚刚的结论 也就是我三分时的函数里 ans是只和x有关的 于是继续推ans和x的关系 就得到了书上的结论 x取中位数即可 所以我又感觉到三分理论上应该是对的了 所以把范围调成了 1e9 然后就过了 。。。 感觉白书上的题 看起来是比较简单的题 其实思路都好难想到啊。。。
数学+中位数定理的做法:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=1000001+5;
const int inf=1e9;
const int maxe=200000;
int a[maxn],c[maxn];
int main()
{
int n;
while(~scnaf("%d",&n))
{
ll ans=0;
ll m=0;
for(int i=0;i<n;i++){
scnaf("%lld",&a[i]);
m+=a[i];
}
m/=n;
for(int i=0;i<n;i++)
{
c[i]=a[i]-m;
if(i)c[i]+=c[i-1];
}
sort(c,c+n);
ll x=c[n/2];
for(int i=0;i<n;i++)
ans+=abs(x-c[i]);
printf("%lld\n",ans);
}
}
写的较搓的三分:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int maxn=1000001+5;
const int inf=1e9;
ll a[maxn],m=0,mid,midmid;
int n;
ll f(ll x)
{
ll ans=0;
for(int i=0;i<n;i++)
{
ans+=abs(x);
x=a[i]+x-m;
}
return ans;
}
int main()
{
while(~scnaf("%d",&n))
{
m = 0;
for(int i=0; i<n; i++)
{
scnaf("%lld",&a[i]);
m += a[i];
}
m /= n;
ll left = -inf;
ll right = inf;
while(right > left+1)
{
mid = (left + right) / 2;
midmid = (mid + right) / 2;
if (f(mid) < f(midmid)) right = midmid-1;
else left = mid;
}
printf("%lld\n",min(f(right),f(left)));
}
}