zoukankan      html  css  js  c++  java
  • Codeforces Round #634 E2. Three Blocks Palindrome (hard version)(双指针/前缀和/二分/好题)

    题目描述

    The only difference between easy and hard versions is constraints.

    You are given a sequence a a a consisting of n n n positive integers.

    Let's define a three blocks palindrome as the sequence, consisting of at most two distinct elements (let these elements are a a a and b b b , a a a can be equal b b b ) and is as follows: [a,a,…,a⏟x,b,b,…,b⏟y,a,a,…,a⏟x] [underbrace{a, a, dots, a}_{x}, underbrace{b, b, dots, b}_{y}, underbrace{a, a, dots, a}_{x}] [xa,a,,a,yb,b,,b,xa,a,,a] . There x,y x, y x,y are integers greater than or equal to 0 0 0 . For example, sequences [] [] [] , [2] [2] [2] , [1,1] [1, 1] [1,1] , [1,2,1] [1, 2, 1] [1,2,1] , [1,2,2,1] [1, 2, 2, 1] [1,2,2,1] and [1,1,2,1,1] [1, 1, 2, 1, 1] [1,1,2,1,1] are three block palindromes but [1,2,3,2,1] [1, 2, 3, 2, 1] [1,2,3,2,1] , [1,2,1,2,1] [1, 2, 1, 2, 1] [1,2,1,2,1] and [1,2] [1, 2] [1,2] are not.

    Your task is to choose the maximum by length subsequence of a a a that is a three blocks palindrome.

    You have to answer t t t independent test cases.

    Recall that the sequence t t t is a a subsequence of the sequence s s s if t t t can be derived from s s s by removing zero or more elements without changing the order of the remaining elements. For example, if s=[1,2,1,3,1,2,1] s=[1, 2, 1, 3, 1, 2, 1] s=[1,2,1,3,1,2,1] , then possible subsequences are: [1,1,1,1] [1, 1, 1, 1] [1,1,1,1] , [3] [3] [3] and [1,2,1,3,1,2,1] [1, 2, 1, 3, 1, 2, 1] [1,2,1,3,1,2,1] , but not [3,2,3] [3, 2, 3] [3,2,3] and [1,1,1,1,2] [1, 1, 1, 1, 2] [1,1,1,1,2] .

    输入格式

    The first line of the input contains one integer t t t ( 1≤t≤104 1 le t le 10^4 1t104 ) — the number of test cases. Then t t t test cases follow.

    The first line of the test case contains one integer n n n ( 1≤n≤2⋅105 1 le n le 2 cdot 10^5 1n2105 ) — the length of a a a . The second line of the test case contains n n n integers a1,a2,…,an a_1, a_2, dots, a_n a1,a2,,an ( 1≤ai≤200 1 le a_i le 200 1ai200 ), where ai a_i ai is the i i i -th element of a a a . Note that the maximum value of ai a_i ai can be up to 200 200 200 .

    It is guaranteed that the sum of n n n over all test cases does not exceed 2⋅105 2 cdot 10^5 2105 ( ∑n≤2⋅105 sum n le 2 cdot 10^5 n2105 ).

    输出格式

    For each test case, print the answer — the maximum possible length of some subsequence of a a a that is a three blocks palindrome.

    题意翻译

    定义 [a,a,…,a⏟x,b,b,…,b⏟y,a,a,…,a⏟x][underbrace{a, a, dots, a}_{x}, underbrace{b, b, dots, b}_{y}, underbrace{a, a, dots, a}_{x}][xa,a,,a,yb,b,,b,xa,a,,a] 这样的序列为TBP,其中 x,yx,yx,y 为自然数(注意 x,yx,yx,y 可以为0)。

    给出一个长为 nnn 的数列 aaa ,求它符合TBP定义的子序列的最长长度。
    TTT 组询问。

    1≤T≤1041 le Tle 10^41T104
    ∑n≤2×105sum n le 2 imes 10^5n2×105
    1≤ai≤2001le a_i le 2001ai200

    输入输出样例

    输入 #1
    6
    8
    1 1 2 2 3 2 1 1
    3
    1 3 3
    4
    1 10 10 1
    1
    26
    2
    2 1
    3
    1 1 1
    输出 #1
    7
    2
    4
    1
    1
    3
    给定三块回文串的定义,求一个序列里包含的最长三块回文串的长度。
    暴力做法是把原序列分成三块,枚举左右端点以及两边、中间部分的颜色。对于hard version过不了。
    首先,要预处理前缀和,使得我们能O(1)地查询l~r区间里x这个数出现的次数,sum[201][N]代表前缀和数组。然后我们先枚举左端点l,求出1~l里a[l]出现的次数cnt(直接查询),然后根据这个次数二分查找右端点,其中右端点r满足r~n区间包含cnt个a[l]。因为不是a[l]的数字之前已经计算过了,所以这里只需要关心新的a[l]即可。因为前缀和数组是单调的,满足二分查找的条件。这里注意很关键的一个地方,有可能有很多个右端点都满足r~n区间包含cnt个a[l],根据贪心的原则我们应该找到最靠右的一个端点,这样能使中间部分尽可能长。所以“前缀和“应该倒着求,配合upper_bound使用。upper_bound(起始地址,结束地址,要查找的数值) 返回的是数值 最后一个 出现的位置。
    这样左右端点确定下来以后,1~200枚举中间部分的数字,对出现次数取最大,再加上两边的数字的出现次数就是候选答案了,与ans比较更新ans即可。
    #include <bits/stdc++.h>
    using namespace std;
    int a[200005],n;
    int sum[202][200005]={0};
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            int ans=1;//ans最小也为1 
            scanf("%d",&n);
            int i,j;
            for(i=1;i<=n;i++) scanf("%d",&a[i]); 
            for(i=0;i<=201;i++)
            {
                for(j=n+1;j>=1;j--)
                {
                    sum[i][j]=0;//清空前缀和数组 
                }
            }
            for(i=1;i<=200;i++)
            {
                for(j=n;j>=1;j--)
                {
                    sum[i][j]=sum[i][j+1]+(a[j]==i?1:0);//倒着存“前缀和”,对于每个j位置所有的i数字都要更新 
                }
            }
            int l,r;
            for(l=1;l<=n;l++)//枚举左端点 
            {
                int num=a[l];//枚举左端点 num是左端点代表的数 
                r=upper_bound(sum[num]+1,sum[num]+n+1,sum[num][1]-sum[num][l+1],greater<int>())-sum[num]-1;//sum数组第二维单调递减,用upper_bound() greater重载 找到最后一个sum数组值等于左区间a[l]出现次数的位置 
                if(!(r>l&&r<=n))continue;//右端点不是合法位置 
                int mid=0;//中间部分最大的出现次数 
                for(j=1;j<=200;j++)//枚举数字 
                {
                    mid=max(mid,sum[j][l+1]-sum[j][r]);//前缀和O(1)查询 
                }
                ans=max(ans,sum[num][r]*2+mid);//更新答案 
            }
            cout<<ans<<endl;
        }
        return 0;
    }
                                                          
  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/12700048.html
Copyright © 2011-2022 走看看