HDU 4746 HDOJ Mophues 2013杭州网赛I题

比赛的时候就预感到这题能出,但是会耗时比较多。结果最后是出了,但是有更简单的题没出。

是不是错误的决策呢?谁知道呢

题目意思:

  定义f(x) = x分解质因数出来的因子个数

    如 x = p0 * p0 * p0 * p1 * p2,则f(x) = 5

    特殊的, f(1) = 0

  求 i = [1..n], j = [1..m] 组成的n*m组(i, j)对中,有多少组f( gcd(i,j) ) <= p

 

 

 

考虑简化版本,p = 0,即求有多少组 gcd(i,j) == 1。

见HDU 1695 http://acm.hdu.edu.cn/showproblem.php?pid=1695

师承叉姐(现在似乎叫御坂姐姐了...)的技能 莫比乌斯函数 + sqrt分块 可到0MS的题。

这题思路其实也大致差不多。

设d(x) 表示 gcd(i, j) 整除 x 的部分,容斥时的权值。

则满足 sigma( d(i) ) (i为x的所有约数) = ( f(x) >= p? 0 : 1 )

喜闻乐见,形如

for(i = 1;i<=n;i++)

  for(j = i;j<=n;j+=i)

的nlogn预处理法

先预处理p=0..18时 每个数字在容斥中占的权值,然后求前缀和,最后sqrt分块计算。

 

Ps:由于题目的n,m范围下,f(x)最大为18,所以当p>18时,答案就为n*m

代码如下:

 1 #include <vector>

 2 #include <cstdio>

 3 #include <cstring>

 4 #include <iostream>

 5 #include <algorithm>

 6 using namespace std;

 7 typedef long long ll;

 8 const int N = 500005;

 9 int pr[N],p[N],cn[N],lp;

10 //预处理素数,和f(x),记为cn[x]

11 void gp(){

12     for(int i=2;i<N;i++){

13         if(!pr[i]){

14             p[lp++]=pr[i]=i;

15             cn[i] = 1;

16         }

17         for(int j=0;j<lp && i*p[j]<N;j++){

18             int num = i*p[j];

19             pr[num] = p[j];

20             cn[num] = cn[i]+1;

21             if(i%p[j] == 0) break;

22         }

23     }

24 }

25 //预处理p = 0..18时的d(x),记为tn[p][x]

26 int tn[19][N];

27 void gtn(){

28     for(int i=0;i<19;i++){

29         tn[i][1] = 1;

30         for(int j=2;j<N;j++){

31             if(cn[j] - i == 1){

32                 for(int k=j;k<N;k+=j)

33                     tn[i][k]--;

34             }

35             else if(cn[j] > i){

36                 int tmp = -1 - (tn[i][j]);

37                 tn[i][j] = tmp;

38                 if(tmp){

39                     for(int k=j+j;k<N;k+=j)

40                     tn[i][k] += tmp;

41                 }

42             }

43         }

44         for(int j=2;j<N;j++) tn[i][j]+=tn[i][j-1];

45     }

46 }

47 void adn(vector<int> &s,int x){

48     s.push_back(0);

49     for(int i=1;i*i<=x;i++){

50         s.push_back(i);

51         s.push_back(x/i);

52     }

53 }

54 ll n,m;

55 int k,*sm;

56 ll gao(){

57     vector<int> num;

58     adn(num,n);

59     adn(num,m);

60     sort(num.begin(),num.end());

61     num.erase(unique(num.begin(),num.end()),num.end());

62     ll ans = 0;

63     int l = num.size();

64     sm = tn[k];

65     for(int i=1;i<l;i++){

66         int d = num[i];

67         ll tmp = sm[d] - sm[num[i-1]];

68         ans += tmp*(ll)(n/d)*ll(m/d);

69     }

70     return ans;

71 }

72 int main(){

73     //freopen("in.txt", "r", stdin);

74     gp();

75     gtn();

76     int T;

77     scanf("%d",&T);

78     while(T--){

79         scanf("%I64d%I64d%d",&n,&m,&k);

80         if(k>18 || (1<<k)>=max(n,m)){

81             printf("%I64d\n",n*m);

82             continue;

83         }

84         printf("%I64d\n",gao());

85     }

86     return 0;

87 }
View Code

 

你可能感兴趣的:(HDU)