zoukankan      html  css  js  c++  java
  • hdu5072 2014 Asia AnShan Regional Contest C Coprime

    最后一次参加亚洲区……

    题意:给出n(3 ≤ n ≤ 105)个数字,每个数ai满足1 ≤ ai ≤ 105,求有多少对(a,b,c)满足[(a, b) = (b, c) = (a, c) = 1] or [(a, b) ≠ 1 and (a, c) ≠ 1 and (b, c) ≠ 1],都互素或都不互素。

    思路:如果是两个数,互素比较好求,边遍历边分解质因子,利用容斥原理即可知道前面与自己互素的有多少。left_prime[i]表示左边与自己互素的,left_no_prime[i]表示左边与自己不互素的数量,同理right表示右边的情况。 

    总用情况减去不合法情况即可,总共情况C(n,3),非法情况有以下几种:

    对于b而言,②④即left_prime[b] * right_no_prime[b],③⑥即left_no_prime[b]*right_prime[b];

    对于a而言,③⑤ 与①④,即right_prime[a] * right_no_prime[a];

    对于c而言,②⑤ 与 ①⑥,即left_prime[c] * left_no_prime[c];

    即可以发现这六个图每个出现了两次,故遍历一遍求出来除以2即是非法情况的数量。

    代码:

    加了个小优化,将100 000个数字,在init时分解质因子,每个数字只分解一次,C++ 300+ms AC

      1 #include <stdio.h>
      2 #include <iostream>
      3 #include <string.h>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 const int MAXN = 100011;
      8 long long prime[MAXN+10];
      9 int getPrime(){
     10     memset(prime,0,sizeof(prime));
     11     for(int i=2;i<=MAXN;i++){
     12         if(!prime[i]) prime[++prime[0]]=i;
     13         for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++){
     14             prime[prime[j]*i]=1;
     15             if(i%prime[j]==0) break;
     16         }
     17     }
     18     return prime[0];
     19 }
     20 
     21 int Stack[MAXN][10], s_top[MAXN];
     22 int arr[MAXN],num[MAXN];
     23 int left_prime[MAXN],left_no_prime[MAXN];
     24 int right_prime[MAXN],right_no_prime[MAXN];
     25 
     26 void factor_full_Stack(){
     27     for(int i = 1;i <= 100000;i ++){
     28         s_top[i] = 0;
     29         int x = i;
     30         for(int j = 1;x != 1;j ++){
     31             if(prime[j] * prime[j] > i){
     32                 Stack[i][s_top[i] ++] = x;
     33                 break;
     34             }
     35             if(x % prime[j] == 0) Stack[i][s_top[i] ++] = prime[j];
     36             while(x % prime[j] == 0) x /= prime[j];
     37         }
     38     }
     39     return ;
     40 }
     41 
     42 void factor(int x){
     43     int end = (1 << s_top[x]);
     44     for(int i = 1;i < end;i ++){
     45         int tmp = 1;
     46         for(int j = 0;j < s_top[x];j ++){
     47             if(i & (1 << j)){
     48                 tmp *= Stack[x][j];
     49             }
     50         }
     51         num[tmp] ++;
     52     }
     53     return ;
     54 }
     55 
     56 int cal_coprime_num(int x){
     57     int res = 0;
     58     int end = (1 << s_top[x]);
     59     for(int i = 1;i < end;i ++){
     60         int cnt = 0,tmp = 1;
     61         for(int j = 0;j < s_top[x];j ++){
     62             if(i & (1 << j)){
     63                 cnt ++;
     64                 tmp *= Stack[x][j];
     65             }
     66         }
     67         if(cnt & 1){
     68             res += num[tmp];
     69         }else{
     70             res -= num[tmp];
     71         }
     72     }
     73     return res;
     74 }
     75 
     76 void init(){
     77     getPrime();
     78     factor_full_Stack();
     79 }
     80 int main(){
     81     init();
     82     int T,n;
     83     scanf("%d",&T);
     84     while(T --){
     85         scanf("%d",&n);
     86         for(int i = 0;i < n;i ++){
     87             scanf("%d",&arr[i]);
     88         }
     89 
     90         memset(num, 0, sizeof(num));
     91         for(int i = 0;i < n;i ++){
     92             left_no_prime[i] = cal_coprime_num(arr[i]);
     93             left_prime[i] = i  - left_no_prime[i];
     94             factor(arr[i]);
     95         }
     96 
     97         memset(num, 0, sizeof(num));
     98         for(int i = n - 1;i >= 0;i --){
     99             right_no_prime[i] = cal_coprime_num(arr[i]);
    100             right_prime[i] = n - i - 1 - right_no_prime[i];
    101             factor(arr[i]);
    102         }
    103 
    104         long long res = (long long)n * (n-1) *(long long)(n-2) / 6;
    105         long long cha = 0;
    106         for(int i = 0;i < n;i ++){
    107             cha += (long long) left_prime[i] * left_no_prime[i];
    108             cha += (long long) left_prime[i] * right_no_prime[i];
    109             cha += (long long) right_prime[i] * left_no_prime[i];
    110             cha += (long long) right_prime[i] * right_no_prime[i];
    111         }
    112         res -= cha / 2;
    113         printf("%I64d
    ",res);
    114     }
    115     return 0;
    116 }
    View Code

     

  • 相关阅读:
    java 多线程
    构造N位格雷码(递归,面向对象)
    字典树trie
    快速排序
    C++ 链表
    15-谜问题(深拷贝、LC检索、面向对象编程)
    [编程题] 扫描透镜(本题还涉及如何从字符串中提取数字)
    python爬虫提取冰与火之歌五季的种子
    带有限期和效益的单位时间的作业排序贪心算法
    0/1背包问题与动态规划
  • 原文地址:https://www.cnblogs.com/-sunshine/p/4076288.html
Copyright © 2011-2022 走看看