zoukankan      html  css  js  c++  java
  • BC div2补题以及 复习模除 逆元__BestCoder Round #78 (div.2)

     第一题没话说 智商欠费 加老柴辅导终于过了

    需要在意的是数据范围为2的63次方-1 三个数相加肯定爆了

       四边形的定义  任意边小于其余三边之和

    换句话说就是  最长边小于其余三边之和

       这样的话问题转化为 最长边依次减其余三边的结果是否小于等于0

    还有一点是题目出现0边 即最小边不为0 想得太多反而把0也算为合法。。。。

       问题只需要 sort一下 判断a[0]==0||a[3]-a[2]-a[1]-a[0]>=0 输出NO //存在0边且最大边大于其他边之和

    第二题 好多种姿势 题目链接http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=683&pid=1002

    官方题解

      我们令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]=2^K-1,再用g[i]表示从这些数中选择若干个数,使得他们的gcd是i的方案数,则g[i]=f[i] - g[j] (对于所有j是i的倍数)。

    由调和级数可以得到复杂度为O(MaxV *log(MaxV))

    DP之二维数组转移

      我们把dp[i][j]作为考虑了第i个数GCD为j的方案数

    直接gcd会超时 所以我们打个表GCD

      那么dp[i][j]+=dp[i-1][j]; dp[i][GCD[j][v[i]]]+=dp[i-1][j]; 然后就可以转移辣;

    #include<cstdio>
    #include<map>
    //#include<bits/stdc++.h>
    #include<vector>
    #include<stack>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<set>
    #include<queue>
    #include<cstdlib>
    #include<climits>
    #define PI acos(-1.0)
    #define INF 0x3fffffff
    using namespace std;
    typedef long long ll;
    typedef __int64 int64;
    const ll mood=1e9+7;
    const int64 Mod=100000007;
    const double eps=1e-9;
    const int N=1005;
    const int MAXN=250050;
    typedef int rl;
    inline void r(rl&num){
        num=0;rl f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
        num*=f;
    }
    int gcd(int a,int b)
    {
        return b==0?a:gcd(b,a%b);
    }
    int v[N];
    int GCD[N][N];
    int64 dp[N][N];
    int main()
    {
        for(int i=1;i<1001;i++)
        {
            for(int j=1;j<=i;j++)
            {
                GCD[i][j]=GCD[j][i]=gcd(i,j);
            }
        }
        int ci;
        r(ci);
        while(ci--)
        {
            int n;
            r(n);
            int mx=-1;
            for(int i=1;i<=n;i++)
            {
                r(v[i]);
                mx=max(mx,v[i]);
                dp[i][v[i]]=1;
            }
            for(int i=2;i<=n;i++)
            {
                for(int j=1;j<=mx;j++)
                {
                    dp[i][j]+=dp[i-1][j];
                    dp[i][j]%=Mod;
                    dp[i][GCD[j][v[i]]]+=dp[i-1][j];
                    dp[i][GCD[j][v[i]]]%=Mod;
                }
            }
            int64 ans=0;
    
            for(int i=1;i<=mx;i++)
            {
    
                ans+=(dp[n][i]*i)%Mod;
                ans%=Mod;
            }
            memset(dp,0,sizeof(dp));
            memset(v,0,sizeof(v));
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    二维

    仔细想了一下 觉得可以优化为滚动数组 试了好久不对 最后瞎蒙

    每个数都多考虑了一次 所以/2需要乘逆元 正好1e8+7是素数

    Mod为素数,那么还可以根据费马小定理得到逆元为 2的(Mod-2)次方%Mod

      即除2等于乘2的(Mod-2)次方%Mod

    所以加了一个快速幂 但是优化为滚动数组后 时间增加了一丢丢 但空间大幅度减少

    16757862 2016-04-03 12:45:34 Accepted 5656 2511MS 5504K 1925 B G++ zxMrlc
    16755798 2016-04-03 00:36:10 Accepted 5656 2449MS 13404K 1722 B G++ zxMrlc

    但是姿势老感觉有问题 等wtw学长指点后我再改改 还有官方的第二个姿势还没有学会。。。衰

    #include<cstdio>
    #include<map>
    //#include<bits/stdc++.h>
    #include<vector>
    #include<stack>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<set>
    #include<queue>
    #include<cstdlib>
    #include<climits>
    #define PI acos(-1.0)
    #define INF 0x3fffffff
    using namespace std;
    typedef long long ll;
    typedef __int64 int64;
    const ll mood=1e9+7;
    const int64 Mod=100000007;
    const double eps=1e-9;
    const int N=1005;
    const int MAXN=250050;
    typedef int rl;
    inline void r(rl&num){
        num=0;rl f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
        num*=f;
    }
    int gcd(int a,int b)
    {
        return b==0?a:gcd(b,a%b);
    }
    int v[N];
    int GCD[N][N];
    int64 dp[N];
    int main()
    {
        int64 xx=Mod-2;
        int64 an=1,t=2;
        while(xx>0)
        {
            if(xx&1) an*=t;
            xx/=2;
            an%=Mod;
            t*=t;
            t%=Mod;
        }
        for(int i=1;i<1001;i++)
        {
            for(int j=1;j<=i;j++)
            {
                GCD[i][j]=GCD[j][i]=gcd(i,j);
            }
        }
    
        int ci;
        r(ci);
        while(ci--)
        {
            int n;
            r(n);
            int mx=-1;
            for(int i=1;i<=n;i++)
            {
                r(v[i]);
                mx=max(mx,v[i]);
            }
    
            for(int i=1;i<=n;i++)
            {
                dp[v[i]]++;
                for(int j=1;j<=mx;j++)
                {
                   // dp[i][j]+=dp[i-1][j];
                    dp[j]%=Mod;
                    dp[GCD[j][v[i]]]+=dp[j];
                    dp[GCD[j][v[i]]]%=Mod;
                }
            }
            int64 ans=0;
            //for(int i=1;i<=mx;i++) cout<<dp[i]<<endl;
            for(int i=1;i<=mx;i++)
            {
    
                ans+=(dp[i]*i)%Mod;
                ans%=Mod;
            }
            memset(dp,0,sizeof(dp));
            memset(v,0,sizeof(v));
            printf("%I64d
    ",ans*an%Mod);
        }
        return 0;
    }
    滚动数组

     我们每次加入的数据会导致翻倍 所以刚才改为加完/2;

    因为添加的v[i]导致的影响就是 当前位置dp[v[i]]多1 即方案数多了选自己的 所以在循环结尾-1就ok了 。。。根本不需要模除 但时间特么变大了

    还是有点模糊的 不太清楚到底怎么回事。

    16758163 2016-04-03 13:17:49 Accepted 5656 2636MS 5504K 1730 B G++ zxMrlc
    #include<cstdio>
    #include<map>
    //#include<bits/stdc++.h>
    #include<vector>
    #include<stack>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<set>
    #include<queue>
    #include<cstdlib>
    #include<climits>
    #define PI acos(-1.0)
    #define INF 0x3fffffff
    using namespace std;
    typedef long long ll;
    typedef __int64 int64;
    const ll mood=1e9+7;
    const int64 Mod=100000007;
    const double eps=1e-9;
    const int N=1005;
    const int MAXN=250050;
    typedef int rl;
    inline void r(rl&num){
        num=0;rl f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
        num*=f;
    }
    int gcd(int a,int b)
    {
        return b==0?a:gcd(b,a%b);
    }
    int v[N];
    int GCD[N][N];
    int64 dp[N];
    int main()
    {
        for(int i=1;i<1001;i++)
        {
            for(int j=1;j<=i;j++)
            {
                GCD[i][j]=GCD[j][i]=gcd(i,j);
            }
        }
    
        int ci;
        r(ci);
        while(ci--)
        {
            int n;
            r(n);
            int mx=-1;
            for(int i=1;i<=n;i++)
            {
                r(v[i]);
                mx=max(mx,v[i]);
            }
    
            for(int i=1;i<=n;i++)
            {
                dp[v[i]]++;
                for(int j=1;j<=mx;j++)
                {
                   // dp[i][j]+=dp[i-1][j];
                    dp[j]%=Mod;
                    dp[GCD[j][v[i]]]+=dp[j];
                    dp[GCD[j][v[i]]]%=Mod;
                }
                dp[v[i]]--;
            }
            int64 ans=0;
            for(int i=1;i<=mx;i++)
            {
    
                ans+=(dp[i]*i)%Mod;
                ans%=Mod;
            }
            memset(dp,0,sizeof(dp));
            memset(v,0,sizeof(v));
            printf("%I64d
    ",ans%Mod);
        }
        return 0;
    }
    滚动第二次优化
  • 相关阅读:
    红队核心工具介绍
    cms漏洞总结(二)
    cms漏洞总结(二)
    cms漏洞总结(二)
    cms漏洞总结(二)
    cms漏洞总结(二)
    cms漏洞总结(二)
    cms漏洞总结 (一)
    好看的樱花落特效
    SELinux 案例 1
  • 原文地址:https://www.cnblogs.com/Geek-xiyang/p/5349677.html
Copyright © 2011-2022 走看看