bzoj 3837 (随机过题法了解一下)

Posted wujiechao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3837 (随机过题法了解一下)相关的知识,希望对你有一定的参考价值。

3837: [Pa2013]Filary

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 395  Solved: 74
[Submit][Status][Discuss]

Description

给定n个正整数,从中挑出k个数,满足:存在某一个m(m>=2),使得这k个数模m的余数相等。
 
求出k的最大值,并求出此时的m。如果有多组解使得k最大,你要在此基础上求出m的最大值。
 

 

Input

第一行一个正整数n(2<=n<=10^5)。
 
第二行n个正整数w[i](1<=w[i]<=10^7)。保证不会出现所有w[i]都相等的情况。
 

 

Output

一行两个整数k,m。保证答案存在。
 

 

Sample Input

6
7 4 10 8 7 1

Sample Output

5 3

HINT


听说大家都喜欢随机过题法,于是我切一道(正解是)随机的题目涨涨姿势。
首先此题在k==2 的时候最小是 $ frac{n}{2} $ 的,以此类推 k==3 时是 $ frac{n}{3} $等等。
那么最小的情况是大于等于$ frac{n}{2} $的,这点毋庸置疑。
那么我们随机一个位置pos,假设a[pos]在这k个数中,找最大的k。
那么我们求a[pos]和每个位置i的差值b[i],然后我们这k个数的 $ gcd gt 1 $ 这个毋庸置疑。那么我们把每个b[i]分解成一堆质数,并记录每个质数出现的位置数。那么最大的k就是质数出现的最大位置数。k对应的最大的m就是这些位置的数的gcd。
而据cls说这个随机期望是logn的。不过你还是多随机个四五次取最大,这样才保险点。
技术分享图片
 1 #include<bits/stdc++.h>
 2 #define clr(x) memset(x,0,sizeof(x))
 3 #define clr_1(x) memset(x,-1,sizeof(x))
 4 #define INF 0x3f3f3f3f
 5 #define LL long long
 6 #define pb push_back
 7 #define mod 1000000007
 8 #define ls(i) (i<<1)
 9 #define rs(i) (i<<1|1)
10 #define mp make_pair
11 #define fi first
12 #define se second
13 using namespace std;
14 const int N=1e7+10;
15 const int M=1e5+10;
16 int inf[N],prime[N],pre[N],g[N],num[N];
17 int tot;
18 int gcd(int a,int b)
19 {
20     int c;
21     while(b)
22         c=a%b,a=b,b=c;
23     return a;
24 }
25 void init()
26 {
27     tot=0;
28     int n=10000000;
29     for(int i=2;i<=n;i++)
30     {
31         if(!inf[i])
32             prime[++tot]=i,pre[i]=tot;
33         for(int j=1;j<=tot && prime[j]*i<=n;j++)
34         {
35             inf[prime[j]*i]=1;
36             pre[prime[j]*i]=j;
37             if(i%prime[j]==0) break;
38         }
39     }
40     return ;
41 }
42 int a[M],b[M];
43 int main()
44 {
45     init();
46     int n,m,k;
47     scanf("%d",&n);
48     for(int i=1;i<=n;i++)
49         scanf("%d",a+i);
50     int p=log10(n)+5;
51     srand(time(0));
52     m=k=0;
53     while(p--)
54     {
55 
56         int pos=rand()%n+1;
57         int tmp=0;
58         int minm=0,mink=0;
59         for(int i=1;i<=n;i++)
60         {
61             b[i]=abs(a[i]-a[pos]);
62             if(!b[i])
63                 tmp++;
64         }
65         for(int i=1;i<=n;i++)
66         {
67             int t=b[i];
68             while(t && t!=1)
69             {
70                 int temp=pre[t];
71                 num[temp]++,g[temp]=gcd(g[temp],b[i]);
72                 if(mink<num[temp]) mink=num[temp],minm=g[temp];
73                 else if(mink==num[temp]) minm=max(g[temp],minm);
74                 while(t%prime[temp]==0) t/=prime[temp];
75             }
76         }
77         if(mink+tmp>k) k=mink+tmp,m=minm;
78         else if(mink+tmp==k) m=max(m,minm);
79         for(int i=1;i<=n;i++)
80         {
81             int t=b[i];
82             while(t && t!=1)
83             {
84                 int temp=pre[t];
85                 num[temp]=0,g[temp]=0;
86                 while(t%prime[temp]==0) t/=prime[temp];
87             }
88         }
89     }
90     printf("%d %d
",k,m);
91     return 0;
92 }
View Code

 




以上是关于bzoj 3837 (随机过题法了解一下)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #451 (Div. 2) F Restoring the Expression

快速记住《计算机文化基础》海量题法

有人在LeetCode上刷过题吗

POJ 2420 模拟退火

BZOJ3671NOI2014随机数据生成器(贪心)

bzoj4282慎二的随机数列