bzoj 3837 (随机过题法了解一下)
Posted wujiechao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3837 (随机过题法了解一下)相关的知识,希望对你有一定的参考价值。
3837: [Pa2013]Filary
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 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
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 }
以上是关于bzoj 3837 (随机过题法了解一下)的主要内容,如果未能解决你的问题,请参考以下文章