• HDU4675【GCD of scequence】【组合数学、费马小定理、取模】


    看题解一开始还有地方不理解,果然是我的组合数学思维比较差哭

    然后理解了之后自己敲了一个果断TLE。。。。哭

    我以后果然还得多练啊哭

    好巧妙的思路啊哭

    知识1:

    费马小定理是数论中的一个重要定理,其内容为:假如p是质数,且(a,p)=1,那么 a^(p-1) ≡1mod p假如p是质数,且a,p互质,那么 a(p-1)次方除以p的余数恒等于1

    对于除法取模还需要用到费马小定理: a ^ (p - 1) % p = 1; -> a ^ (p - 2) % p = (1 / a) % p;

    巧妙1:

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

    { int temp; scanf("%d",&temp); sum1[temp]++; }

    for(int j=i;j<=m;j+=i) sum+=sum1[j];

    直接判断倍数是否有无。奋斗ORZ!!!

    用这一块代码,这样再从1遍历到m的时候,速度增加非常快,然后就不会超时。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cstring>
    #include <cmath>
    #include <ctime>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <queue>
    #include <set>
    #include <map>
    #include <vector>
    #include <assert.h>
    
    using namespace std;
    
    #define lowbit(i) (i&-i)
    #define sqr(x) ((x)*(x))
    #define enter printf("
    ")
    #define is_sqr(x) (x&(x-1))
    #define pi acos(-1.0)
    #define clr(x)  memset(x,0,sizeof(x))
    #define fp1 freopen("in.txt","r",stdin)
    #define fp2 freopen("out.txt","w",stdout)
    #define pb push_back
    
    typedef __int64 LL;
    
    const double eps = 1e-7;
    const double DINF = 1e100;
    const int INF = 1000000006;
    const LL LINF = 1000000000000000005ll;
    const int MOD = (int) 1e9 + 7;
    const int maxn=300005;
    
     template<class T> inline T Min(T a,T b){return a<b?a:b;}
     template<class T> inline T Max(T a,T b){return a>b?a:b;}
     template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
     template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
    
    
    LL f[maxn],e[maxn],a[maxn],ans[maxn],sum1[maxn];
    LL quick_pow(LL a,LL b)//a的b次方,快速幂取模
    {
        LL ret=1;
        while(b)
        {
            if(b&1) ret=(ret*a)%MOD;
            b/=2;
            a=(a*a)%MOD;
        }
        return ret%MOD;
    }
    LL cal(LL n,LL k)
    {
        if(k==0||n==k) return 1;
        return (f[n]*e[k]%MOD)*e[n-k]%MOD;//注意运算顺序
    }
    
    //以后某些变量还是不采用C99的写法了
    int main()
    {
      f[0]=e[0]=1;
      for(int i=1;i<=maxn;i++)
      {
          f[i]=f[i-1]*i%MOD;
          e[i]=quick_pow(f[i],MOD-2);
      }
      int n,m,k;
      while(scanf("%d%d%d",&n,&m,&k)!=EOF)
      {
          clr(sum1);
          for(int i=1;i<=n;i++)
          {
             int temp;
             scanf("%d",&temp);
             sum1[temp]++;
          }
          for(int i=m;i>=1;i--)//倒着写不至于每次都m/i次循环
          {
              int sum=0;
              for(int j=i;j<=m;j+=i)
                sum+=sum1[j];
              if(sum<n-k)//k个不一样的,n-k个一样的。
              {
                  ans[i]=0;continue;
              }
              ans[i]=((cal(sum,n-k)*quick_pow(m/i-1,sum-(n-k))%MOD)*quick_pow(m/i,n-sum))%MOD;
              for(int j=2*i;j<=m;j+=i)
                  ans[i]=(ans[i]-ans[j]+MOD)%MOD;
          }
          for(int i=1;i<m;i++) printf("%lld ",ans[i]);
          printf("%lld
    ",ans[m]);
      }
      return 0;
    }
    
    


     

  • 相关阅读:
    最后一次不用看脸的日子
    经典算法_指针
    #include <process.h>
    经典算法_文件
    stdin、stdout、stderr
    经典算法_位运算
    经典算法_结构体
    经典算法_字符串
    #include <string.h>
    #include <stdio.h>
  • 原文地址:https://www.cnblogs.com/james1207/p/3263019.html
Copyright © 2020-2023  润新知