zoukankan      html  css  js  c++  java
  • HDU 5514 题解

    题意:给出n和m,代表有n只青蛙和m颗标号为0~m-1的石子,m颗石子围成一个圈,给出n个数据ai表示一只青蛙一次能跳多少步,求最终所有被青蛙踩过的石子的标号和。

    1<=N<=10000,1<=m<=1e9,1<=ai<=1e9;共1~20组数据,1000MS

    算法/思路:容斥原理:首先为了方便处理,将ai变为gcd(ai,m)(用数论知识可以证明结果不变),然后使用容斥原理,当然不能用2n那么多次操作的方法,于是有一个较为巧妙的方法,求出m的所有因子(约为log2m个),并从小到大排序,然后对第i个因子,依次判断每个ai是否有经过它,有则将vis[i]记为1,否则为0,并将所有num[i]初始化为0(num数组用于表示某数用过多少次),最后从小到大扫描每个因子Ai,令ans+=(vis[i]-num[i])*(Ai*(m/Ai-1)/2),并扫描所有比Ai大的因子Ak,若Ak是Ai的倍数,则num[k]+=(vis[i]-num[i]),这样显然每个数最终只使用一次(相当于容斥时直接判断数被重复利用了几次)。算法复杂度O(log2m(n+log2m))

     

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
        
    const int maxn=10005;
        
    int t,n,m,sq,tot;
    int a[maxn+5];
    vector<int> vis,num;
    vector<long long> x;
    long long ans;
        
    int gcd(int x,int y){if (y==0) return x;else return gcd(y,x%y);}
        
    void init(){
        x.clear();tot=1;ans=0;
        vis.clear();num.clear();
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    }
        
    int main()
    {
        scanf("%d",&t);
        for (int q=1;q<=t;++q){
            init();
            sq=floor(sqrt(m)+0.5);
            x.push_back(1);//故初始化tot=1; 
            for (int i=2;i<=sq;++i) if (m%i==0){
                x.push_back(i);++tot;
                if (m/i==i) continue;
                x.push_back(m/i);++tot;
            }
            vis.resize(tot,0);num.resize(tot,0);
            //for (int i=0;i<x.size();++i) {printf("%d%d
    ",vis[i],num[i]);}
            sort(x.begin(),x.end());
            for (int i=1;i<=n;++i){
                a[i]=gcd(m,a[i]);
                for (int j=0;j<x.size();++j) if (x[j]%a[i]==0) vis[j]=1;
            }
            //for (int i=0;i<x.size();++i) {printf("%d%d
    ",vis[i],num[i]);}
            for (int i=0;i<x.size();++i) if (vis[i]!=num[i]){
                ans+=m*(m/x[i]-1)/2*(vis[i]-num[i]);
                    
                for (int j=i+1;j<x.size();++j) if (x[j]%x[i]==0) num[j]+=vis[i]-num[i];
            }
            printf("Case #%d: %lld
    ",q,ans);
        }
    }
  • 相关阅读:
    jQuery里的$.ajax()方法详解
    express框架使用axios进行post请求, 两次请求问题
    electron-vue 报错 Unresolved node modules: bufferutil, utf-8-validate, canvas
    electron-vue离线打包
    个推技术:性能提升60%↑ 成本降低50%↓ Spark性能调优看这篇就够了!
    百亿级日志流分析实践 | 剖析个推后效分析功能实现原理
    iOS开发常用国外网站清单
    一篇文章搞定Git——Git代码管理及使用规范
    音视频技术入门——音频处理
    Java内存空间知识点梳理
  • 原文地址:https://www.cnblogs.com/terra/p/7018861.html
Copyright © 2011-2022 走看看