UVA11300 分金币

一道涉及数学和中位数定理的编程题,通过设定不同数值范围来解决超界问题,最终确定当第一个分配者给第二个x个金币时,x取中位数为解。
摘要由CSDN通过智能技术生成

非常棒的一道题 看了就觉得是三分 三分第一个给第二个多少  其他的可以推出来  而时间上应该没问题  但是范围会出问题  如果是把范围订为定为 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)));
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值