• Lucky Numbers(枚举,计数)


    题意

    给定一个长度为\(N - 1\)的整数序列\(S = (S_1, S_2, \dots, S_{N-1})\)以及\(M\)个不同的被称为幸运数的整数\(X_1, X_2, \dots, X_M\)

    一个长度为\(N\)的整数序列\(A = (A_1, A_2, \dots, A_N)\)满足如下条件时被称为好序列:

    • 对于任意\(i = 1, 2, \dots, N - 1\),有:\(A_i + A_{i + 1} = S_i\)

    找到幸运数出现次数最多的好序列,输出幸运数出现次数。

    题目链接:https://atcoder.jp/contests/abc255/tasks/abc255_e

    数据范围

    \(2 \leq N \leq 10^5\)
    \(1 \leq M \leq 10\)
    \(-10^9 \leq S_i \leq 10^9\)
    \(-10^9 \leq X_i \leq 10^9\)
    \(X_1 < X_2 < \cdots < X_M\)

    思路

    常规操作,求一下\(A\)\(S\)的关系,不妨设\(A_1 = Z\)

    \(A_1 + A_2 = S_1\)得:\(A_2 = S_1 - Z\);由\(A_2 + A_3 = S_2\)得:\(A_3 = S_2 - S_1 + Z\)\(A_3 + A_4 = S_3\)得:\(A_4 = S_3 - S_2 + S_1 - Z\);......

    通过上面的分析,我们发现对于\(i = 1, 2, \dots, N\),有:\(A_i = (-1)^{i + 1}Z + B_i\)。其中对于\(i=2,\dots, N\)\(B_i = -B_{i - 1} + S_{i - 1}\)\(B_1 = 0\)

    现在问题就转化成了:确定\(Z\),使得序列中幸运数字出现次数最多。

    我一开始的做法是枚举序列中的每个数字\(A_i\),二重循环枚举所有幸运数字\(X_j\),分别求出当\(A_i\)等于\(X_j\)时,\(Z\)的值。在此之前,分别使用两个map记录加减\(Z\)时的\(B_i\)出现次数(分别表示为\(neg\)\(pos\)。当\(i\)是奇数时,\(B_i\)放进\(pos\)中;否则,\(B_i\)放进\(neg\)中)。然后,枚举每个幸运数字\(X_k\),推算满足要求的\(B_i\)(当加\(Z\)时,\(B_i = X_k - Z\);当减\(Z\)时,\(B_i = X_k + Z\)),得到出现次数(\(pos[X_k - Z] + neg[X_k + Z]\))。这个做法是\(O(NM^2 \log N)\)的,被卡掉了。

    下面介绍正解。我们需要考虑如何优化掉\(O(M)\)的时间复杂度。我们发现,在枚举的过程中,有\(A_i = (-1)^{i + 1}Z + B_i = X_j\),即:\(Z = (-1)^{i + 1}(X_j - B_i)\)。我们令\(Z_{i, j} = (-1)^{i + 1}(X_j - B_i)\)。同时,我们使用map维护\(Z_{i, j}\)的个数。\(Z_{i, j}\)的个数的意义是,当\(A_1 = Z_{i, j}\)时,序列中有多少个元素为幸运数字。

    因此,最终答案就是出现次数最多的\(Z_{i, j}\)。时间复杂度为\(O(NM \log NM)\)

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 100010, M = 15;
    
    int n, m;
    ll s[N], x[M];
    ll a[N];
    map<ll, ll> mp;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i < n; i ++) scanf("%lld", &s[i]);
        for(int i = 1; i <= m; i ++) scanf("%lld", &x[i]);
        for(int i = 2; i <= n; i ++) {
            a[i] = -a[i - 1] + s[i - 1];
        }
        ll ans = 0;
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m; j ++) {
                ll t = x[j];
                ll A;
                if(i % 2 == 0) A = a[i] - t;
                else A = t - a[i];
                mp[A] ++;
            }
        }
        for(auto p : mp) ans = max(ans, p.second);
        printf("%lld", ans);
        return 0;
    }
    
  • 相关阅读:
    iframe的使用小贴士
    jquery M97-datepicker日历控件
    CSS z-index 属性的使用方法和层级树的概念
    常用的js代码
    图片水平垂直居中
    server端和前端的区别
    nodejs模块化标准
    nodejs介绍
    小程序缓存Storage的基本用法
    小程序数据绑定的拓展用法
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/16371293.html
Copyright © 2020-2023  润新知