zoukankan      html  css  js  c++  java
  • HDU7073 Integers Have Friends 2.0

    传送门


    这题真有意思。题目还特意说了是最近一场cf的加强版,结果跟cf那道题的做法几乎是完全不一样,竟然用随机过掉了。


    先说一下cf那道题的题意:给一个长度为(n)的序列(a),让你选择一个最长的子区间([l,r]),满足(exists m),使得所有(a_i in [l,r])( extrm{mod} m)意义下同余,输出最长子区间长度。

    对于这道题,我们只要预处理出差分数组,然后选择最长的区间,满足该区间内的最大公约数大于(1)即可。我当时用st表预处理+二分写的。


    而今天的比赛题,将子区间改成了子序列。

    这就大有不同了,首先应该发现的是,答案必然大于等于(lceil frac{n}{2} ceil),即当(m=2)时的答案。

    这一点,为接下来的随机化算法提供了理论依据:我们随机两个位置(x,y),那么(a_x,a_y)都在答案中的最长子序列的概率必然不小于(frac1{4}).如果随机(K)次并取每一次的最大值,那么失误的概率就是((frac{3}{4})^K),当(K=30)的时候就是(10^{-3})级别了,可几乎认为是正确的了。

    因此我们随机(K)次,然后每次随机,用(|a_x-a_y|)的所有质因子作为模数去求最长子序列长度,这样时间复杂度就是(O(Kp(sqrt{ extrm{max} a_i})+11nK)),其中(p(n))表示(n)以内的质数个数,是(O(frac{n}{log n}))级别,(11)(4*10^{12})以内不同的质数的个数。

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define In inline
    typedef long long ll;
    typedef double db;
    const int maxn = 3e6 + 5;
    const int K = 30;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n;
    ll a[maxn];
    
    bool vis[maxn];
    int p[maxn], pcnt = 0;
    In void init()
    {
    	for(int i = 2; i < maxn; ++i) if(!vis[i])
    	{
    		p[++pcnt] = i;
    		for(int j = i; 1LL * j * i < maxn; ++j) vis[j * i] = 1;
    	}
    }
    
    In int check(ll p, ll r)
    {
    	int cnt = 0;
    	for(int i = 1; i <= n; ++i) cnt += (a[i] % p == r);
    	return cnt;
    }
    In int solve()
    {
    	int ret = 1;
    	for(int k = 1; k <= K; ++k)
    	{
    		int x = rand() % n + 1, y = rand() % n + 1;
    		while(x == y) x = rand() % n + 1, y = rand() % n + 1;
    		ll tp = abs(a[x] - a[y]);
    		for(int i = 1; 1LL * p[i] * p[i] <= tp; ++i)
    		{
    			if(tp % p[i] == 0)
    			{
    				ret = max(ret, check(p[i], a[x] % p[i]));
    				while(tp % p[i] == 0) tp /= p[i];
    			}
    		}
    		if(tp > 1) ret = max(ret, check(tp, a[x] % tp));
    	}
    	return ret;
    }
    
    int main()
    {
    	srand(time(0));
    	init();
    	int T = read(); 
    	while(T--)
    	{
    		n = read();
    		for(int i = 1; i <= n; ++i) a[i] = read();
    		write(solve()), enter;
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于剪切板
    编译器选项
    【转】预编译头没有使用的问题
    【转】fatal error C1900: “P1”(第“20081201”版)和“P2”(第“20080116”版)之间 Il 不匹配
    pImpl
    HIVE 2.3.4 本地安装与部署 (Ubuntu)
    计算机网络 自顶向下 复习提要 数据链路层
    计算机网络 自顶向下 复习提要 网络层2
    计算机网络 自顶向下 复习提要 网络层
    计算机网络 自顶向下 复习提要 传输层(TCP)
  • 原文地址:https://www.cnblogs.com/mrclr/p/15154243.html
Copyright © 2011-2022 走看看