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 }
    尽最大的努力,做最好的自己!
  • 相关阅读:
    scala之伴生对象的继承
    scala之伴生对象说明
    “Failed to install the following Android SDK packages as some licences have not been accepted” 错误
    PATH 环境变量重复问题解决
    Ubuntu 18.04 配置java环境
    JDBC的基本使用2
    DCL的基本语法(授权)
    ZJNU 1374
    ZJNU 2184
    ZJNU 1334
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5351006.html
Copyright © 2011-2022 走看看