Codeforces Round #631 (Div. 2) B. Dreamoon Likes Permutations

题目链接:Codeforces Round #631 (Div. 2) B. Dreamoon Likes Permutations

题意:给定整数数组a,将a分为两个数组p1、p2,使p1、p2同时满足条件:若数组长度为k,则数组中出现1~k的所有数。

解题思路:

1、将条件分解
长度为k的数组中出现1~k的所有数等价于:
①出现k个数 ②这k个数的和是1~k的和

2、
对条件①,用set容器保存当前出现的所有数,set.size( )即为不重复的数的个数。若到第k个数,set.size( ) == k,则条件①满足。(不用set容器也可以,只要能记录出现的不重复的数的个数就行)

对条件②,用一个变量sum在循环过程中记录1~k的和,再与数组第1个到第k个数字的和比较。若到第k个数,数组和 == sum,则条件②满足。

3、
在t点将a分为p1、p2,若p1、p2都满足条件①②,则t点是一个答案。

这个做法因为记录了前缀和,所以不能用int记录,不然会在第8个测试点出错。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<utility>
using namespace std;

const long long INF = ~0ull>>2;
const int Inf = 0x3f3f3f3f;
const int maxn = 2e6+5;
bool flag[maxn];
int n;
vector<pair<int, int> > res;

/*node[i].cnt指直到位置i,一共出现了多少个不重复数
node[i].val指到i的前缀和*/
struct tagnode{
    long long cnt, val;
}node[maxn];

void init()
{
    fill(flag, flag+n+5, false);
    res.clear();
    node[0].val = 0;
    return;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--){
        scanf("%d", &n);
        init();

        set<int> kase;
        long long sum = 0;
        for (int i = 1; i <= n; i++){
            sum += i;

            long long a;
            scanf("%lld", &a);
            kase.insert(a);
            node[i].val = node[i-1].val + a; //求前缀和
            node[i].cnt = kase.size();
            /*node[i].cnt == i 指满足条件①
              node[i].val == sum 指满足条件②
              两个条件都满足,则这个p1满足条件*/
            if (node[i].cnt == i && node[i].val == sum)
                flag[i] = true;
            //flag[i] == true 指以i点为分割点,p1满足条件
        }

        /*要p1、p2都满足条件,还要考察p2*/
        kase.clear();
        sum = 0;
        for (int i = n; i >= 1; i--){
            //sum也是从1加到n
            sum += n-i+1;

            long long a = node[i].val - node[i-1].val;
            long long sum_b = node[n].val - node[i-1].val;//后缀和
            kase.insert(a);
            /*kase.size() == n-i+1 指满足条件①
              sum_b == sum 指满足条件②
              两个条件都满足,则这个p2满足条件
              flag[i-1] == true 指这个p2对应的p1满足条件
              若p1、p2都满足条件,则分割点i是一个答案*/
            if (kase.size() == n-i+1 && sum_b == sum && flag[i-1]){
                pair<int, int> temp;
                temp.first = i-1;   //i-1是p1的长度
                temp.second = n-i+1;//n-i+1是p2的长度
                res.push_back(temp);
            }
        }

         printf("%d\n", res.size());
        for (int i = 0; i < res.size(); i++)
            printf("%d %d\n", res[i].first, res[i].second);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值