HZNU2019校赛-Little Sub and Counting(小撒布与计数)(函数的单调性)

Description

Little Sub likes Math. Now he has a simple counting problem for you.

小撒布喜欢数学,现在他有个简单问题要问你。
Given an positive integer sequence A, for each Ai, Please calculate how many elements Aj in the sequence satisfied Ai^Aj > Aj^Ai.

给定一个正整数序列A,对于每个Ai,请计算多少个序列内的Aj使得 Ai^Aj > Aj^Ai成立。

Input

The first line contains one positive integer n(1 ≤ n ≤ 100000).、

第一行包含一个正整数n

The following line contains n positive integers Ai(1 ≤ Ai ≤ 2^31 − 1).

接下来是n个正整数ai

Output

Please output n integer in one line and separate them by a single space. The ith integer indicates the answer concerning Ai.

在一行内输出n个整数。第i个整数是有关Ai的答案。

Samples

input:

3 1 2 5

output:

0 2 1

乍一看这个式子很要命——你中有我,我中有你。但是凭借直觉把两侧取对数,从而把指数变成乘积关系时,就有了一个很有意思的关系:

\large \frac{ln(a[j])}{a[j]}>\frac{ln(a[i])}{a[i]}

很明显这是一个函数,那么问题就变成了:

对于函数\large f(x)=\frac{lnx}{x},当给定x的定义域(大于等于1的非连续无序数集)时,他们分别大于多少个函数值?

对函数进行求导,可知函数在x∈(0,e]时单调递增,x∈[e,正无穷]的时候单调递减。根据计算:f(3)为最大值,且f(2)=f(4)。

所以得到如下结论:

  1. f(3)一定大于除了其余f(3)之外的所有函数值
  2. f(1)等于0,且值域内其他数都大于0,所以f(1)肯定最小。
  3. 根据函数单调性f(2)=f(4),大于除了f(3),f(4),f(2)的值。

那么就得到了一些特殊关系(count为某个数的个数):

   ans(1)=0,ans(2)=n-count(3)-count(2)-count(4),ans(3)=n-count(3),ans(4)=ans(2)

至于大于4的点,就是根据单调性逐一递减(相同的数除外)了,除了递推,我们还可以用两个神奇的二分函数:

注意:有序时才可用

std::lower_bound(起始地址,终止地址,值),这个函数返回一个地址,代表第一个大于或等于这个值的数的地址。

std::upper_bound(起始地址,终止地址,值),这个函数同样返回一个地址,代表第一个严格大于这个值的数的地址。

顺便一说,如果用返回的地址减去数组首地址,那这个位置就变成了数组下标。

当然由于这个题里面恶心的输出模式,我们不能直接把原数组给排序了,所以要复制一个副本,以副本为基准进行排序并二分。

所以有如下思路

  1. 根据数学知识解得函数的单调性,找出规律,列举所有特殊点的关系
  2. 复制原数组,对副本进行排序
  3. 利用二分函数与特殊点的关系,对每个点进行遍历,找到属于每个点的答案。 

代码如下:

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const long long int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod=1000000007;
const int tool_const=1999112620000907;
const int tool_const2=33;
inline int Unnamed_Scanner()
{
    int tmp=0,si=1;
    char c=getchar();
    while(c>'9'||c<'0')
    {
        if(c=='-')
            si=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        tmp=tmp*10+c-'0';
        c=getchar();
    }
    return si*tmp;
}
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
ll ans[5266465];
ll ans2[5266465];
ll cnt[5];
int DETERMINATION()
{
    ll n;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>ans[i];
        if(ans[i]<=4)
            cnt[ans[i]]++;//统计这些特殊值的个数
    }
    memcpy(ans2,ans,sizeof(ans));//复制数组
    sort(ans2+1,ans2+n+1);//对副本排序
    for(int i=1;i<=n;i++)
    {
        if(ans[i]==1)//特殊值的相关操作
            cout<<0<<" ";
        else if(ans[i]==2)
            cout<<n-cnt[2]-cnt[3]-cnt[4]<<" ";
        else if(ans[i]==3)
            cout<<n-cnt[3]<<" ";
        else if(ans[i]==4)
            cout<<n-cnt[2]-cnt[3]-cnt[4]<<" ";
        else
            cout<<n+cnt[1]-(lower_bound(ans2+1,ans2+1+n,ans[i]+1)-ans2-1)<<" ";
           //一般值的处理是:总数减去比他大的值的数组下标,再把1加上(多减了1,因为f(1)是最小值所以不能减去)
        if(i==n)
            cout<<endl;
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值