【Codeforces Round 276 (Div 2)D】【数论 正难则反 枚举倍数 二分 O(nlogn)】Maximum Value n个数大数mod小数找最大余数

D. Maximum Value
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a sequence a consisting of n integers. Find the maximum possible value of  (integer remainder of ai divided by aj), where 1 ≤ i, j ≤ n and ai ≥ aj.

Input

The first line contains integer n — the length of the sequence (1 ≤ n ≤ 2·105).

The second line contains n space-separated integers ai (1 ≤ ai ≤ 106).

Output

Print the answer to the problem.

Sample test(s)
input
3
3 4 5
output
2



【Codeforces Round 276 (Div 2)D】【数论 正难则反 枚举倍数 二分 数组优化O(nlogn)】Maximum Value n个数大数mod小数找最大余数

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=2e5+10,M=2e6+10,Z=1e9+7,ms63=1061109567;
int n;
int a[N],b[M];
int main()
{
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;++i)scanf("%d",&a[i]);
		sort(a+1,a+n+1);a[n+1]=a[n]<<1;
		for(int i=1;i<=n;++i)
		{
			for(int j=a[i];j<a[i+1];++j)b[j]=a[i];
		}
		int ans=0;
		for(int i=n-1;i>=1;--i)
		{
			if(a[i]+1<=ans)break;
			if(a[i]==a[i+1])continue;
			for(int x=a[i]+a[i]-1;x<a[n+1];x+=a[i])
			{
				gmax(ans,b[x]%a[i]);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
【trick&&吐槽】
哇哈!尝试优化,暴力剪枝竟然AC啦~~
用错误的做法AC一道题果然是心里最开心的2333

【题意】
给你n(2e5)个数,每个数的数值都在[1,1e6]之间,让你求出max(a[i]%a[j]),a[i]>=a[j]]。

【类型】
数论

【分析】 
我们假设这n个数已经按照从小到大的顺序形成了从前到后的排序。
那么——如果没有a[i]>=a[j]的限制,答案肯定是max(a[x]),a[x]!=a[n]
然而,现在有a[i]>=a[j]的要求了。我们怎么做呢?

我当时做的第一种做法,是枚举大的数,然后找小的数,来更新答案,这种算法时间复杂度是O(nsqrt(n)log(n))会TLE。
然而,做题的时候竟然没有想到反过来。
就是我们找素数的时候,枚举数找因子的时间复杂度是O(nsqrt(n))
可是如果转换一下次序,枚举数筛倍数的时间复杂度就只有O(nlog(n))了。

这题也一样。
1,枚举因子找倍数,对于一个因子的一个倍数,我们找比这个倍数小的最大的数(通过lower_bound()-1实现)
2,从大到小枚举做剪枝
这题就在O(nlogn(n)log(n))的时间做完啦。
此外,先可以贪心x(x/2+1)为ans,可以起到优化作用。

PS:
因为a[]的数值并不大。
所以,我们可以用另外一种做法,直接记录<=x的数中最大的数为b[x]。然后我们就可以O(1)查询。
就可以达到整体上O(nlogn)的时间复杂度啦。啦啦啦啦~

【时间复杂度&&优化】
O(nlogn logn)->O(nlogn)

*/

【Codeforces Round 276 (Div 2)D】【数论 正难则反 枚举倍数 二分】Maximum Value n个数大数mod小数找最大余数

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=2e5+10,M=1e6+10,Z=1e9+7,ms63=1061109567;
int n;
int a[N];
bool e[M];
int main()
{
	while(~scanf("%d",&n))
	{
		MS(e,0);
		for(int i=1;i<=n;++i){scanf("%d",&a[i]);e[a[i]]=1;}
		sort(a+1,a+n+1);a[n+1]=1e9;
		int ans=0;
		for(int i=n;i>1;--i)if(e[a[i]]&&e[a[i]/2+1])gmax(ans,a[i]%(a[i]/2+1));
		for(int i=n-1;i>=1;--i)
		{
			if(a[i]+1<=ans)break;
			if(a[i]==a[i+1])continue;
			int p=i;
			while(1)
			{
				int x=(a[p]/a[i]+1)*a[i];
				p=lower_bound(a+p,a+n+1,x)-a-1;
				gmax(ans,a[p]%a[i]);
				if(++p>n)break;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
【trick&&吐槽】
哇哈!尝试优化,暴力剪枝竟然AC啦~~
用错误的做法AC一道题果然是心里最开心的2333

【题意】
给你n(2e5)个数,每个数的数值都在[1,1e6]之间,让你求出max(a[i]%a[j]),a[i]>=a[j]]。

【类型】
数论

【分析】 
我们假设这n个数已经按照从小到大的顺序形成了从前到后的排序。
那么——如果没有a[i]>=a[j]的限制,答案肯定是max(a[x]),a[x]!=a[n]
然而,现在有a[i]>=a[j]的要求了。我们怎么做呢?

我当时做的第一种做法,是枚举大的数,然后找小的数,来更新答案,这种算法时间复杂度是O(nsqrt(n)log(n))会TLE。
然而,做题的时候竟然没有想到反过来。
就是我们找素数的时候,枚举数找因子的时间复杂度是O(nsqrt(n))
可是如果转换一下次序,枚举数筛倍数的时间复杂度就只有O(nlog(n))了。

这题也一样。
1,枚举因子找倍数,对于一个因子的一个倍数,我们找比这个倍数小的最大的数(通过lower_bound()-1实现)
2,从大到小枚举做剪枝
这题就在O(nlogn(n)log(n))的时间做完啦。
此外,先可以贪心x(x/2+1)为ans,可以起到优化作用。

PS:
因为a[]的数值并不大。
所以,我们可以用另外一种做法,直接记录<=x的数中最大的数为v[x]。然后我们就可以O(1)查询。
就可以达到整体上O(nlogn)的时间复杂度啦。啦啦啦啦~

【时间复杂度&&优化】
O(nlogn logn)->O(nlogn)

*/


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值