sdust 2681 求个最大值 (数学+思维)

49 篇文章 0 订阅
37 篇文章 0 订阅


Problem J: 求个最大值

Time Limit: 1 Sec   Memory Limit: 64 MB
Submit: 60   Solved: 14
[ Submit][ Status][ Web Board]

Description

 给出n(1 <= n <= 200000)个数字ai(1 <= ai <= 1000000),i为数字的下标,按输入顺序从1开始编号一直到n,求满足ai >= aj的最大的ai % aj。

Input

第一行一个数字n,第二行n个整数。

Output

题目要求的最大值。

Sample Input

22 3

Sample Output

1

这题比赛里已经想到思路了,就是不知道怎么去表示。。 思路很简单,设a, b , a > b -> a/b = k....r(r是余数),这样我们肯定希望a离着k*b越元越好。也就是我们枚举倍数的时候(比赛中写过枚举倍数,但是n*n的。。)我们希望b*k离着a越远越好,但是不能远过b的大小,这样就难处理了,但是可以转化成 (k+x)*b离着a越近越好,那枚举到每个数的倍数时候,对他有用的就只有一个离着这个数最近的a【i】了、、前缀处理下就好了。。记录1-maxn*2每个数比他小但是最大的a[i]就行。。


补充:

这题还可以二分做。。群里看到的

 枚举每个j 对于j枚举他的倍数 然后在数组里二分
 根据调和级数第二步是log的 
 因为你模的最大值应该是最接近他倍数的吧。。 
比如:
 假如ai的倍数2*ai存在的话
 那么最靠近2*ai并且小于2*ai的数mod ai最大

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 10;
int b[maxn], a[maxn];
int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        memset(b, 0, sizeof(b));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
        }
        sort(a+1, a+1+n);
        int index = a[1]+1;
        a[n+1] = maxn*2;
        for(int i = 2; i <= n+1; i++)
        {
            while(index <= a[i])
            {
                b[index++] = a[i-1];
            }
        }
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            for(int j = a[i]*2; j <= maxn*2; j += a[i])
                ans = max(ans, b[j]%a[i]);
        }
        printf("%d\n", ans);
    }
    return 0;
}

二分代码:

#include<bits/stdc++.h>
using namespace std;

int a[200010];

int main() {
	int n;
	cin>>n;

	for(int i=0;i<n;i++)
	 cin>>a[i];

	sort(a, a+n);

	n = unique(a, a+n) - a;

	int ans = 0;
	for(int i=0; i<n; i++) {
		int cur = a[i];
		cur += a[i];
		while(1) {
			int j = lower_bound(a, a+n, cur) - a;
			j--;
			if(j>=0 && a[j] > a[i]) {
				ans = max(ans, a[j]%a[i]);
			}
			if(cur > a[n-1])
			   break;
			cur += a[i];
		}
	}

	cout << ans << endl;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值