zoukankan      html  css  js  c++  java
  • 数学(GCD,计数原理)HDU 5656 CA Loves GCD

    CA Loves GCD

    Accepts: 135
    Submissions: 586
    Time Limit: 6000/3000 MS (Java/Others)
    Memory Limit: 262144/262144 K (Java/Others)
    问题描述
    CA喜欢是一个热爱党和人民的优秀同♂志,所以他也非常喜欢GCD(请在输入法中输入GCD得到CA喜欢GCD的原因)。
    现在他有N个不同的数,每次他会从中选出若干个(至少一个数),求出所有数的GCD然后放回去。
    为了使自己不会无聊,CA会把每种不同的选法都选一遍,CA想知道他得到的所有GCD的和是多少。
    我们认为两种选法不同,当且仅当有一个数在其中一种选法中被选中了,而在另外一种选法中没有被选中。
    输入描述
    第一行 T,表示有 T 组数据。
    接下来 T 组数据,每组数据第一行一个整数 N,表示CA的数的个数,接下来一行 N 个整数 Aii​​ 表示CA的每个数。
    1≤T≤50, 1≤N≤1000, 1≤Ai≤10001 le T le 50,~1 le N le 1000,~1 le A_i le 10001T50, 1N1000, 1Ai​​1000
    输出描述
    对于每组数据输出一行一个整数表示CA所有的选法的GCD的和对 100000007 取模的结果。
    
    输入样例
    2
    2
    2 4
    3
    1 2 3
    输出样例
    8
    10

    所有数据∈[1,1000]
      这次的BestCoder没打,从没见过这么难的第二题。
      我们令dp[i][j]表示在前i个数中,选出若干个数使得它们的gcd为j的方案数,于是只需要枚举第i+1个数是否被选中来转移就可以了。
      令第i+1个数为v,当考虑dp[i][j]的时候,我们令dp[i+1][j] += dp[i][j],dp[i+1][gcd(j,v)] += dp[i][j]
      复杂度O(N*MaxV) MaxV 为出现过的数的最大值。
      其实有O(MaxV *log(MaxV))的做法,我们考虑记f[i]表示从这些数中选择若干个数,使得他们的gcd是i的倍数的方案数。假如有K个数是i的倍数,则f[i]=2K-1,再用g[i]表示从这些数中选择若干个数,使得他们的gcd是i的方案数,则g[i]=f[i] - Σ(j是i的倍数)g[j] 。
      由调和级数可以得到复杂度为O(MaxV *log(MaxV))
      
      还是挺巧妙的!
    TLE的DP(MB卡常数):
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 const int maxn=1010;
     6 const int mod=100000007;
     7 int dp[maxn][maxn],a[maxn];
     8 int Gcd(int a,int b){
     9     return b?Gcd(b,a%b):a;
    10 }
    11 int main(){
    12     int T,n,maxv;
    13     scanf("%d",&T);
    14     while(T--){
    15         memset(dp,0,sizeof(dp));
    16         scanf("%d",&n);maxv=0;
    17         for(int i=1;i<=n;maxv=max(maxv,a[i]),i++)
    18             scanf("%d",&a[i]);
    19         for(int i=0;i<=n;i++)dp[i][0]=1;
    20         for(int i=1;i<=n;i++){
    21             for(int j=0;j<=maxv;j++)dp[i][j]=dp[i-1][j];
    22             for(int j=0;j<=maxv;j++)
    23                 (dp[i][Gcd(j,a[i])]+=dp[i-1][j])%=mod;
    24         }
    25         int ans=0;    
    26         for(int j=1;j<=maxv;j++)
    27             (ans+=dp[n][j]*j)%=mod;
    28         printf("%d
    ",ans);        
    29     }
    30     return 0;
    31 }

    第二种方法的AC程序:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 using namespace std;
     5 const int maxn=1010;
     6 const int mod=100000007;
     7 long long f[maxn],g[maxn],ans;
     8 int main(){
     9     int T,n;
    10     scanf("%d",&T);
    11     while(T--){
    12         scanf("%d",&n);
    13         memset(f,0,sizeof(f));
    14         for(int i=1,x;i<=n;i++){
    15             scanf("%d",&x);
    16             for(int j=1;j<=x;j++){
    17                 if(x%j==0)
    18                     f[j]++;    
    19             }
    20         }
    21         for(int i=1;i<=1000;i++){
    22             long long ret=1;
    23             for(int j=1;j<=f[i];j++)
    24                 (ret*=2)%=mod;
    25             ret-=1;    
    26             f[i]=ret;
    27         }
    28         for(int i=1000;i>=1;i--){
    29             g[i]=f[i];
    30             for(int j=2*i;j<=1000;j+=i)
    31                 (g[i]-=g[j])%=mod;
    32         }
    33         ans=0;
    34         for(int i=1;i<=1000;i++)
    35             (ans+=g[i]*i)%=mod;
    36         printf("%lld
    ",(ans+mod)%mod);    
    37     }
    38     return 0;
    39 }
    尽最大的努力,做最好的自己!
  • 相关阅读:
    c++ this *this
    名称空间
    c++ 静态持续变量
    c++ 数组
    c++ 头文件
    实例化和具体化详解
    在linux下安装eclipse以及运行c++程序的安装步骤
    在centos (linux) 搭建 eclipse c++开发分环境
    Linux上使用Qt Creator进行C/C++开发
    使用Qt Creator 2.60编写C/C++程序
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5351006.html
Copyright © 2011-2022 走看看