(CF1284B)New Year and Ascent Sequence

原题链接

思路:

首先将原序列分为两类:有正序对的和没有正序对的.

对于有正序对的序列,统计其个数.

对于没有正序对的序列,记录其最大值和最小值。用数组 Amax 与 Amin 存储.

假设合成的序列为 A+B, 则 A+B 有正序对有正序对的条件为:

  1. A 或 B 有正序对

  1. A,B 均无正序对且 A 的最小值小于 B 的最大值

对于条件 (2), 将数组 Amin 与 Amax 排序后可用尺取法计数.

对于条件 (1), 假设有 c 个有正序对的序列, 使用容斥原理可得其数量为 2*c*n-n*n

需要注意的是答案有可能超出 int 范围,所以要用 long long 类型

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstdio>
#include <algorithm>
using namespace std;
const int Mn(100500);
int amin[Mn],amax[Mn]; //最大/最小值数组
int main()
{
int n;
scanf("%d",&n);
int cac(0),cdc(0); //有正序对的序列数量和没有正序对的序列数量
for(int i(1);i<=n;++i)
{
int l;
scanf("%d",&l);
int la(0x7fffffff),amn(0x7fffffff),amx(0); //a[i-1],序列最小/最大值
bool isac(false); //是否有正序对
for(int i(1);i<=l;++i)
{
int a;
scanf("%d",&a);
amn = a<amn ? a : amn;
amx = a>amx ? a : amx;
if(a>la) isac = true; //若a[i]>a[i-1]则代表有正序对
la = a;
}
if(isac)
++cac;
else
{ amax[++cdc]=amx; amin[cdc]=amn; }
}
sort(amax+1,amax+cdc+1); //排序
sort(amin+1,amin+cdc+1);
amax[0] = -1;
long long ans(0);
int pmn(1),pmx(0);
for(;pmn<=cdc;++pmn) //尺取
{
for(;pmx<=cdc;++pmx)
if(amax[pmx]>amin[pmn]) break;
ans += cdc-pmx+1;
}
ans += 2ll*cac*n-1ll*cac*cac;
printf("%lld",ans);
return 0;
}