atcoder abc-162

作者: waaagh | 来源:发表于2020-04-25 15:24 被阅读0次

    E - Sum of gcd of Tuples (Hard)

    题目大意:N个数,数的范围1~K,可以组成KN个序列,求所有序列gcd的和。
    算法:快速幂
    思路:从序列->gcd->和这条线不好走,倒过来想,gcd有多少种可能?答案是从1到K。那对最大公约数i有几个?是不是也就是N个数中i的倍数有几个?答案是N/i。注意,最大公约数i的个数是不是包含2*i的个数,要减掉。
    实现:从大大小找,因为大的要减小的,另外手写快速幂而不是直接pow(),因为会超范围。
    代码:

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<cmath>
    
    #define LL  long long
    #define MAXK    100010
    #define P   1000000007
    using namespace std;
    int N, K;
    LL cnt[MAXK];
    LL ans = 0;
    int main()
    {
        scanf("%d%d", &N, &K);
        for(int i=K; i>=1; i--) {
            int t = K/i;
            cnt[i] = pow(t, N);
            for(int j=i+i; j<=K; j+=i) {
                cnt[i] -= cnt[j];
                cnt[i] %= P;
            }
    //        printf("%d %d\n", i, cnt[i]);
            ans += cnt[i]*i;
            ans %= P;
        }
        cout << ans << endl;
        return 0;
    }
    

    F - Select Half

    题目大意:从N个数中找\lfloor N/2 \rfloor个不相邻序列组成的最大和。
    算法:dp
    思路:先想出二维dp,设dp[i][j]: i个数中j个不相邻序列组成大最大值,dp[i][j] = max(dp[i-1][j], dp[i-2][j-1]+A[i]),前面代表不取第i个数,后面代表取第i个数,要不相邻所以i-2。超时。只能减状态,i肯定不能,只能考虑j。
    到第i个数,最多取\lfloor (i+1)/2 \rfloor个,题目最多\lfloor N/2 \rfloor,剩余N-i+1最多\lfloor (N-i+1)/2 ,\rfloor\lfloor N/2 \rfloor - \lfloor (N-i+1)/2 \rfloor = \lfloor i/2 \rfloor\lfloor i/2 \rfloor <=j <= \lfloor (i+1)/2 \rfloor,最多三个状态。
    实现:二维dp循环时注意j<=i/2,因为题目要求取N/2个。一维dp对于j只有三个状态,可以用map解决。
    代码一O(n2):

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<cmath>
    
    #define LL  long long
    //#define MAXN    200010
    #define MAXN    20010
    #define P   1000000007
    using namespace std;
    int N;
    int A[MAXN];
    int dp[MAXN][MAXN/2];
    
    int main()
    {
        cin>>N;
        for(int i=1; i<=N; i++) {
            cin>>A[i];
        }    
        memset(dp, 0, sizeof(dp));
        dp[1][1] = A[1]; dp[2][1] = max(A[1], A[2]);
        for(int i=2; i<=N; i++) {
            for(int j=1; j<=i/2; j++) {
                dp[i][j] = max(dp[i-1][j], dp[i-2][j-1]+A[i]);
    
            }
        }
    /*
        int i, j;
        i = N;j=N/2;
        cout<<"select:"<<endl;
        while(i&&j) {
            if(sel[i][j] != 0) {
                cout<<A[sel[i][j]]<<endl;
                i-=2;
                j-=1;
            }else {
                i-=1;
            }
        }
        */
        cout << dp[N][N/2] << endl;
    
        return 0;
    }
    
    

    代码二O(n):

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<map>
    
    #define LL  long long
    #define MAXN    200010
    #define P   1000000007
    using namespace std;
    int N;
    int A[MAXN];
    map<int, LL> dp[MAXN];
    
    //atcoder abs162-F
    int main()
    {
        cin>>N;
        for(int i=1; i<=N; i++) {
            cin>>A[i];
        }    
        dp[1][0] = 0; dp[1][1] = A[1];
        dp[2][0] = 0; dp[2][1] = max(A[1], A[2]);
        for(int i=3; i<=N; i++) {
            for(int j=i/2-1; j<=(i+1)/2; j++) {
                // 小心dp[i][j]   未被赋值默认0遇负数max可能出错
                if(dp[i-1].count(j)) {
                    dp[i][j] = dp[i-1][j];
                }
                if(dp[i-2].count(j-1)) {
                    if(!dp[i].count(j))
                        dp[i][j] = dp[i-2][j-1]+A[i];
                    else dp[i][j] = max(dp[i][j], dp[i-2][j-1]+A[i]);
                }
            }
        }
    
        cout << dp[N][N/2]<<endl;
        return 0;
    }
    

    参考:
    https://img.atcoder.jp/abc162/editorial.pdf

    相关文章

      网友评论

        本文标题:atcoder abc-162

        本文链接:https://www.haomeiwen.com/subject/hilkwhtx.html