混沌DM

DM Hunter

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

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

题目意思:

  定义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

 

posted on 2013-09-18 15:32  混沌DM  阅读(1199)  评论(0编辑  收藏  举报