部分配列の説明と特別なトピック

サブ配列: 配列内の選択された連続要素で構成される新しい配列を指します。

例 1: 6900。完全なサブ配列の数を数えます。

正の整数 の配列が 与えられます nums 。

配列内の部分配列が次の条件を満たす場合、それは 完全な部分配列と呼ばれます 。

  • 部分配列内の 個別要素の数は 、配列全体内の個別の要素の数と同じです。

配列内の完全な部分配列の数を返します  。

サブ配列 は、配列内の連続した空ではないシーケンスです。

例 1:

入力: nums = [1,3,1,2,2]
出力: 4
説明:完全な部分配列は次のとおりです: [1,3,1,2]、[1,3,1,2,2]、[3, 1,2] および [3,1,2,2]。

例 2:

入力: nums = [5,5,5,5]
出力: 10
説明:配列は整数 5 のみで構成されているため、どの部分配列も完全な部分配列の条件を満たします。サブアレイの総数は 10 です。

ヒント:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 2000

アイデア: 1. set コンテナーと unowned_set コンテナーを使用した暴力的な列挙

           2. 引き違い窓

ACコード:

//暴力
class Solution {
public:
    int countCompleteSubarrays(vector<int>& nums) 
    {
        int sum=0;
        set<int> s;
        for(auto& x:nums)
        s.insert(x);
        int l=nums.size();
        for(int i=0;i<l;i++)
        {
            unordered_set<int> ss;
            for(int j=i;j<l;j++)
            {
                ss.insert(nums[j]);
                if(s.size()==ss.size())
                sum++;
            }
        }
        return sum;
    }
};
//滑动窗口
class Solution {
public:
    int countCompleteSubarrays(vector<int> &nums) {
        int m = unordered_set<int>(nums.begin(), nums.end()).size();
        unordered_map<int, int> cnt;
        int ans = 0, left = 0;
        for (int v: nums) { // 枚举子数组右端点 v=nums[i]
            cnt[v]++;
            while (cnt.size() == m) {
                int x = nums[left++];
                if (--cnt[x] == 0)
                    cnt.erase(x);
            }
            ans += left; // 子数组左端点 < left 的都是合法的
        }
        return ans;
    }
};

例 2: 5057. 配列の切り詰め

長さ n の正の整数配列 a1、a2、…、an と正の整数 p が与えられます。

ここで、この配列を中央で切り詰めて、空でない2 つの部分配列を取得したいと思います。

配列の値は、p を法とした配列内のすべての要素の合計に等しいと規定します。

指定された配列を切り捨てた後、取得される2 つの空ない部分配列の値の合計ができるだけ大きくなるようにしたいと考えています。

これら 2 つの空部分配列の値の合計の最大値を出力してください。

入力フォーマット

最初の行には 2 つの整数 n と p が含まれています。

2 行目には n 個の整数 a1、a2、…、an が含まれます。

出力フォーマット

可能な最大の値の合計を表す整数。

データ範囲

最初の 33 のテスト ポイントは 2≤n≤10 を満たします。
すべてのテスト ポイントは 2≤n≤1e5、2≤p≤10000、1≤ai≤1e6 を満たします。

入力例1:

4 10
3 4 7 2

出力サンプル 1:

16

入力例2:

10 12
16 3 24 13 9 8 7 5 12 12

出力サンプル 2:

13

アイデア: プレフィックスの合計 + 列挙

ACコード:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+10;
int a[N],n,p,sum[N],ans;
int sumn;
void solve()
{
    cin>>n>>p;
    for(int i=0;i<n;i++){
        cin>>a[i];
        sumn += a[i];
    }
    sum[0] = a[0];
    for(int i=1;i<n;i++){
        sum[i] = sum[i-1]+a[i];
    }
    if(n == 2){
        int cnt = a[0] % p + a[1] % p; 
        cout<<cnt<<endl;
        return ;
    }
    for(int i=1;i<n-1;i++){
        int tmp = sum[i-1]%p+(sumn-sum[i-1])%p;
        ans = max(ans,tmp);
    }
    cout<<ans<<endl;
    return ;
}
signed main()
{
	int t=1;
	while(t--)
	solve();
	return 0;
}

本日のおすすめ音楽:Lonely Lover

次の記事: Codeforces ラウンド 889 (ディビジョン 2)

おすすめ

転載: blog.csdn.net/weixin_74088105/article/details/132011006