数学题

hdu1060 Leftmost Digit

题意:

计算nn的第一位数字

思路:

把nn转化为科学计数法nn=a * 10x,其中a是浮点数,x是整数。我们要的答案就是(int)a。
现在想办法计算这个a:
左右同时取以10为底的对数,则式子变为:nlg(n)=lg(a)+x。
发现只需要知道x的值就能计算出a,因为x是科学计数法10的幂次,所以x=lg(nn)向下取整,即x=nlg(n)向下取整。
然后就能计算出a=10lg(nlg(n)-x)

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        int x=n*log10(n);
        int ans=pow(10,n*log10(n)-x);
        cout<<ans<<endl;
    }
    return 0;
}

bzoj1045: [HAOI2008] 糖果传递

题意:

有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
求使所有人获得均等糖果的最小代价。

思路:
设f[i]是i给i+1的糖果数量,ave是糖果均值
则:
f[2]=f[1]+a[2]-ave;
f[3]=f[2]+a[3]-ave=f[1]+a[2]+a[3]-2*ave
...
f[i]=f[1]+(a[2]+...a[i])-(i-1)*ave;
设s[i]=(i-1)*ave-(a[2]+...a[i]);
则f[i]=k-s[i];(必须要转化成这样的减法形式,下面才能取中位数)
最后的答案是|f[1]|+|f[2]|...+|f[n]|
|f[i]|=|k-s[i]|,|k-s[i]|类似坐标系x轴上某一点k到其他所有点s[i]的距离和
我们知道要使得|k-s[i]|最小,k应该是s[i]中的中位数
知道k就可以直接计算答案f[],然后计算出答案了
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
int a[maxm];
int s[maxm];
signed main(){
    int n;
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum+=a[i];
    }
    int ave=sum/n;
    for(int i=2;i<=n;i++){
        s[i]=s[i-1]+ave-a[i];
    }
    sort(s+1,s+1+n);
    int ans=0;
    for(int i=1;i<=n;i++){
        ans+=abs(s[n/2]-s[i]);
    }
    cout<<ans<<endl;
    return 0;
}

CodeForces1328 F. Make k Equal

题意:

给一个长度为n的数组a,和一个整数k,
现在你能进行两种操作:
1.把数组中最大的数减1
2.把数组中最小的数加1

你可以进行操作无限次,问最少进行多少次操作之后可以使得数组中有k个相同的数。

思路:

最后相同的数一定是原数组中已经存在的数
假设这个相同的数为x,
如果要把至少一个小于x的数变为x,那么一定要把所有小于x的数先变为x-1,
如果要吧至少一个大于x的数变为x,那么一定要把所有大于x的数先变为x+1,

先对a(i)排序+去重,记得记录每个数出现的次数
预处理出把小于a(i)的数全部变为a(i)-1和把大于a(i)的数全部变为a(i)+1的花费

枚举最后相同的数a(i),对于每个a(i)分类讨论:
如果将小于(或者大于)a(i)的若干数变为a(i)能够凑到k个,计算一下然后取min更新答案
如果将小于(或者大于)a(i)的数全部变为a(i)还是不够,那么就用另外一遍的凑,计算一下然后min更新答案。

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
map<int,int>mark;
int l[maxm];//l[i]表示i左边全部a[i]-1的花费
int r[maxm];//r[i]表示i右边全部a[i]+1的花费
int lc[maxm];//lc[i]表示i以及左边一共多少个数
int rc[maxm];//rc[i]表示i以及右边一共多少个数
int cnt[maxm];//cnt[i]表示a[i]的个数
int sum[maxm];//cnt[i]*a[i]的前缀和
int a[maxm];
signed main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mark[a[i]]++;
    }
    sort(a+1,a+1+n);
    n=unique(a+1,a+1+n)-a-1;
    for(int i=1;i<=n;i++){//cnt[]
        cnt[i]=mark[a[i]];
    }
    for(int i=1;i<=n;i++){//lc[]
        lc[i]=lc[i-1]+cnt[i];
    }
    for(int i=n;i>=1;i--){//rc[]
        rc[i]=rc[i+1]+cnt[i];
    }
    for(int i=1;i<=n;i++){//sum[]
        sum[i]=sum[i-1]+cnt[i]*a[i];
    }
    for(int i=1;i<=n;i++){//l[]
        l[i]=lc[i-1]*(a[i]-1)-sum[i-1];
    }
    for(int i=n;i>=1;i--){//r[]
        r[i]=(sum[n]-sum[i])-rc[i+1]*(a[i]+1);
    }
    int ans=sum[n];
    for(int i=1;i<=n;i++){//计算答案
        if(cnt[i]>=k){//已经有k个了
            ans=0;
            break;
        }
        if(lc[i-1]>=k-cnt[i]){//左边够
            ans=min(ans,l[i]+k-cnt[i]);
        }else{//左边不够
            ans=min(ans,l[i]+lc[i]+(k-cnt[i]-lc[i])+r[i]);
        }
        if(rc[i+1]>=k-cnt[i]){//右边够
            ans=min(ans,r[i]+k-cnt[i]);
        }else{//右边不够
            ans=min(ans,r[i]+rc[i]+(k-cnt[i]-rc[i])+l[i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值