• 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*m);
    82             continue;
    83         }
    84         printf("%I64d
    ",gao());
    85     }
    86     return 0;
    87 }
    View Code
  • 相关阅读:
    测试代码运行效率
    用宏实现的单例模式
    上传控件的按钮改为图片
    ODAC的使用笔记
    ASP.NET防止重复提交
    向SharePoint图片库添加Item
    获取页面上用户控件的子控件ID
    SharePoint的WebService的应用
    GridView中HyperLinkField的链接使用JavaScript问题
    C#日期验证的正则表达式
  • 原文地址:https://www.cnblogs.com/hundundm/p/3328501.html
Copyright © 2020-2023  润新知