zoukankan      html  css  js  c++  java
  • AGC003D Anticube

    题目链接

    对于一个数的唯一分解:(x=p_1^{k_1} imes p_2^{k_2} imes cdots imes p_n^{k_n}),显然我们把每个 (k_i) 都对 (3) 取模对答案没有任何影响(除了 (x) 本身就是完全立方数的特殊情况)。

    考虑取模后每一个 (x) 都有唯一确定的 (y) 使得 (x imes y) 是一个完全立方数,我们显然可以贪心的选择 (x,y) 中数量较多的并 ban 掉另一个。

    现在问题的关键是如何取模呢?直接分解质因数时间复杂度显然不能容忍。

    考虑先把 (10^{frac {10} 3}) 以内的质因子全部筛掉,现在一个数 (x) 只有三种情况:

    1. 最后剩的数是 (1),是特殊情况,拉到一起特判处理。
    2. 剩的数不是完全立方数,那么对立面就一定是这个数的平方。
    3. 是完全平方数,对立面是这个数的二次方根。

    可以用 (map) 记录每个数出现的次数,最后注意所有完全立方数只能取一个。时间复杂度 (O(sqrt[3]{V}nlogn))

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<map>
    #include<cmath>
    #define int long long
    
    using namespace std;
    
    const int N = 100009, K = 2200;
    int n, a[K + 9], p[K + 9], b[N], cnt;
    map <int, int> Map, Rev;
    
    void prework()
    {
    	for (int i = 2; i <= K; i++)
    	{
    		if (!a[i])	
    			a[i] = i, p[++cnt] = i;
    		for (int j = 1; j <= cnt; j++)
    		{
    			if (p[j] > a[i] || p[j] > K / i)
    				break;
    			a[p[j] * i] = p[j];
    		}
    	}
    }
    
    void init()
    {
    	scanf("%lld", &n);
    	for (int i = 1; i <= n; i++)
    		scanf("%lld", &b[i]);
    }
    
    void work()
    {
    	int qwq = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		int x = 1, rev = 1;
    		for (int j = 1; j <= cnt; j++)
    			if (b[i] % p[j] == 0)
    			{
    				int tmp = 0;
    				while (b[i] % p[j] == 0)
    					tmp++, b[i] /= p[j];
    				tmp %= 3;
    				if (tmp == 1) x *= p[j], rev *= p[j] * p[j];
    				else if (tmp == 2)
    					x *= p[j] * p[j], rev *= p[j];
    			}
    		x *= b[i];
    		int Sqr = (int)sqrtl(b[i]);
    		if (Sqr * Sqr == b[i])
    			rev *= Sqr;
    		else if (rev <= 1e18 / b[i] / b[i])
    			rev *= b[i] * b[i];
    		else rev = -1;
    		if (x == 1) qwq = 1;
    		else Rev[x] = rev, Map[x]++;
    	}
    	int ans = 0;
    	map <int, int> ::iterator it;
    	for (it = Map.begin(); it != Map.end(); it++)
    	{
    		int FI = it -> first, SE = it -> second;
    		if (Rev[FI] == -1)
    		{
    			ans += SE;
    			continue;
    		}
    		if (Rev[FI] == -2) continue;
    		ans += max(SE, Map[Rev[FI]]);
    		Rev[Rev[FI]] = -2;
    	}
    	printf("%lld
    ", ans + qwq);
    }
    
    signed main()
    {
    	prework();
    	init();
    	work();
    	return 0;
    }
    
    
  • 相关阅读:
    windows server 2019安装
    python 求相关系数
    MySQL的Sleep进程占用大量连接解决方法
    mysql show processlist分析
    mysql5.6常用查询sql
    使用exe4j将java项目打成exe执行程序
    MediaWIKI部署流程
    谈谈Activiti中流程对象之间的关系
    EhCache RMI 分布式缓存/缓存集群
    Tomcat8安装, 安全配置与性能优化
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13818363.html
Copyright © 2011-2022 走看看