zoukankan      html  css  js  c++  java
  • CDOJ 1314 Hash Perfectly FFT

    Hash Perfectly

    题目连接:

    http://acm.uestc.edu.cn/#/problem/show/1314

    Description

    In computing, a hash table is a data structure used to implement an associative array, a structure that can map keys to values.

    A hash table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found. A common hash function is (index=key \% array\_size) ((\%) is modulo operator), but it may cause some collisions.

    For example, if keys are (1,2,6,10), and we choose (array\_size=4), the indexes will be (1,2,2,2), where some collisions happen.

    To solve the collision, we can use the method known as separate chaining with linked lists.

    Seeing the example again, when we try to insert (6), because its index (2) is used, we build a linked list in index (2), and there would be (2 ightarrow 6) in index (2). Insert (10) next, there would be a linked list (2 ightarrow 6 ightarrow 10) in index 2.

    To calculate the efficiency of the hash function, we define a value called (ASL) (Average search length):

    [ASL=frac{1}{n}sum_{i=1}^{n}c_i ]

    (c_i) is the number of times to compare when we search the (i^{th}) key.

    Using the example above again, (c_1=1,c_2=1,c_3=2,c_4=3), so (ASL=frac{1}{4}(1+1+2+3)=1.75).

    It's obvious that (ASL) can minimize when we choose a sufficiently large (array\_size), but in fact due to the limitation of memory, (array\_size) must be no more than (limit), i.e., (1leq array\_sizeleq limit).

    Now you are given n keys, try to choose a proper (array\_size) to minimize (ASL). If there are multiple answers, choose the smallest one.

    Input

    The first line contains two integers (n) and (limit).

    The second line contains (n) integers, where (i^{th}) integer indicates the (i^{th}) key.

    (1leq n, limit, keyleq 2*10^5)

    Output

    Print the smallest (array\_size) which can minimize (ASL).

    Sample Input

    4 4
    1 2 6 10

    Sample Output

    3

    Hint

    题意

    现在你有n个数,然后哈希是指b[i]=a[i]%k

    现在让你找到一个合适的k,使得冲突的对数最少,这个k需满足0<=k<=limit

    题解:

    若一个位置冲突了k次,则对n*ASL的贡献是k*(k+1)/2,相当于k个数两两冲突的对数加k。
    对于两个数a,b,他们只会在(a-b) % array_size == 0时冲突。
    利用FFT,可把所有a-b的可能取值对应的个数算出来。对于每个array_size,算出a-b=array_size, a-b=2array_size, a-b=3array_size, …的个数,就可以直接得到ASL的值。
    复杂度O(nlogn)

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 600040;
    const double pi = acos(-1.0);
    
    int len=1<<19;
    
    struct Complex
    {
        double r,i;
    	Complex(double r=0,double i=0):r(r),i(i) {};
    	Complex operator+(const Complex &rhs)
    	{
    		return Complex(r + rhs.r,i + rhs.i);
    	}
    	Complex operator-(const Complex &rhs)
    	{
    		return Complex(r - rhs.r,i - rhs.i);
    	}
    	Complex operator*(const Complex &rhs)
    	{
    		return Complex(r*rhs.r - i*rhs.i,i*rhs.r + r*rhs.i);
    	}
    } va[N],vb[N];
    
    void rader(Complex F[],int len)	//len = 2^M,reverse F[i] with  F[j] j为i二进制反转
    {
    	int j = len >> 1;
    	for(int i = 1;i < len - 1;++i)
    	{
    		if(i < j) swap(F[i],F[j]);	// reverse
    		int k = len>>1;
    		while(j>=k)
    		{
    			j -= k;
    			k >>= 1;
    		}
    		if(j < k) j += k;
    	}
    }
    
    void FFT(Complex F[],int len,int t)
    {
    	rader(F,len);
    	for(int h=2;h<=len;h<<=1)
    	{
    		Complex wn(cos(-t*2*pi/h),sin(-t*2*pi/h));
    		for(int j=0;j<len;j+=h)
    		{
    			Complex E(1,0);	//旋转因子
    			for(int k=j;k<j+h/2;++k)
    			{
    				Complex u = F[k];
    				Complex v = E*F[k+h/2];
    				F[k] = u+v;
    				F[k+h/2] = u-v;
    				E=E*wn;
    			}
    		}
    	}
    	if(t==-1)	//IDFT
    		for(int i=0;i<len;++i)
    			F[i].r/=len;
    }
    
    void Conv(Complex a[],Complex b[],int len) //求卷积
    {
    	FFT(a,len,1);
    	FFT(b,len,1);
    	for(int i=0;i<len;++i) a[i] = a[i]*b[i];
    	FFT(a,len,-1);
    }
    int n,limit;
    int a[N];
    long long num[N],sum[N];
    void solve()
    {
        scanf("%d%d",&n,&limit);
        int Mx = 0;
        for(int i=0;i<n;i++)
        {
            int x;scanf("%d",&a[i]);
            va[a[i]].r+=1;
            vb[200000-a[i]].r+=1;
        }
        Conv(va,vb,len);
        for(int i=0;i<=200000;i++)
            num[i]=(long long)(va[200000+i].r+0.5);
        long long ans1=1e18,ans2=0;
        for(int i=1;i<=limit;i++)
        {
            long long cnt = 0;
            for(int j=i;j<=len;j+=i)
                cnt+=num[j];
            if(cnt<ans1)
            {
                ans1=cnt;
                ans2=i;
            }
        }
        cout<<ans2<<endl;
    }
    int main()
    {
        solve();
    	return 0;
    }
  • 相关阅读:
    To Do List
    Linux 替换文本中对空格为下划线
    Jumpserver开源堡垒机
    用jmeter编写脚本做实时线上监控
    Supervisor使用详解
    Python模块之pysnooper
    Java读取json文件并进行处理
    IOS APP自动化测试 真机测试 遇到的坑
    测试人员入职必须了解的东西包括下面一些内容
    linux 和MacBook下的批替换
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5380044.html
Copyright © 2011-2022 走看看