zoukankan      html  css  js  c++  java
  • 牛客NOIPtg day5 B-demo的gcd

    一句话题意:给定长度为n的序列,求任意两两之间gcd的积mod 998244353的值。

    好像是莫比乌斯反演板子题???(反正noip估计不考这种毒瘤

    考场上想到一个类似正解的思路 好像摊下来最多处理nlogn次就义无反顾地写了结果爆零

    (你以为for while if continue 都不要时间的啊

    后来一看发现自己的思路貌似毫无问题,就是实现丑了(逃

     

    可以看到对于每一个质数p,对答案的贡献为p^k(k-1) 其中k=序列中包含质因数p的数个数

    然后对于质数的幂次p^q,考场上的思路是每次计算质数之后将原序列中的该质数除掉,如此循环直到找不到该质因数为止(于是就T了还不如暴力qvq

    其实可以考虑另一种很简单的思路 对于任意一个p^k,枚举他的倍数,对答案的贡献即为p^k'(k'-1),与上述等价,复杂度为O(nlogn)(其实是ln

    代码如下

    #include <cstdio>
    #include <iostream>
    #define qvq register
    #define int long long
    using namespace std;
    const int mod=998244353;
    const int maxn=1000005;
    int p[maxn],cnt,a[maxn];
    bool np[maxn];
    
    inline int read() {
        int x=0,f=1;
        char cr=getchar();
        while (cr>'9' || cr<'0') {
            if (cr=='-') f=-1;
            cr=getchar();
        }
        while (cr>='0' && cr<='9') {
            x=(x<<3)+(x<<1)+cr-'0';
            cr=getchar();
        }
        return x*f;
    }
    
    inline void euler() {
        for (qvq int i=2;i<=1000000;i++) {
            if (!np[i]) p[++cnt]=i;
            for (qvq int j=1;j<=cnt && p[j]*i<=1000000;j++) {
                np[p[j]*i]=1;
                if (i%p[j]==0) break;
            }
        }
    }
    
    inline int val(int k) {
        return k*(k-1)/2;
    }
    
    inline int power(int a,int b,int p) {
        if (b==0) return 1;
        if (b==1) return a;
        if (b&1) return a*power(a*a%p,b>>1,p)%p;
        else return power(a*a%p,b>>1,p);
    }
    
    int num[maxn],f[maxn];
    
    signed main() {
        int n=read();
        int lim=-1;
        for (qvq int i=1;i<=n;i++) a[i]=read(),num[a[i]]++,lim=max(lim,a[i]);
        euler();
        for (int i=1;i<=cnt;i++) {
            int temp=p[i];
            while (temp<=1000000) {
                f[temp]=p[i];
                temp*=p[i];
            }
        }
        int ans=1;
        for (int i=1;i<=lim;i++) {
            if (!f[i]) continue;
            int res=0;
            for (int j=i;j<=lim;j+=i) res+=num[j];
            ans*=power(f[i],val(res),mod),ans%=mod;
        }
        printf("%lld",ans);
    }

    我太菜了orz

  • 相关阅读:
    Linux下安装软件遇见的问题汇总
    使用AlarmManager定期执行工作
    android打开文件、保存对话框、创建新文件夹对话框(转载)
    一些算法的整理
    安卓adb调试命令常见的问题
    java下的串口通信-RXTX
    Unity 协程运行时的监控和优化
    Unity3D 协程的介绍和使用
    游戏服务器:到底使用UDP还是TCP
    Unity 可重复随机数
  • 原文地址:https://www.cnblogs.com/YoOXiii/p/11407320.html
Copyright © 2011-2022 走看看