初见安~这里是传送门:Codeforces 1284B
Sol
这个题好像有很多人没看懂题呀……解释一下:就是给你n个数字串,现在要你从中选两个进行前后拼接,可以自己接自己,并且两个不同的串A和B,A-B和B-A是两种接法。现在定义要求是串中存在某个值前面出现了一个比他小的值,求满足要求的拼接有多少个。
样例二的话,7种拼接为:【用ABC给三个串标号】AA,AB,AC,BA,CA,BC,BB。
抓住两个要点就可以了:
1.如果某个串本身就是满足要求的,那么它可以和所有剩下的串进行拼接,有2n-1种。
2.两个串拼接,如果前一个串的最小值小于后面一个串的最大值,拼起来就是合法的。
对于第二个要点我们很好处理,把每个串的最大值和最小值扔到两个数组里面排序后累加答案就好了,线性的。但是加上第一个要点后细节就有点多了,因为很容易加重复。假设现在剩下x个串,我们处理到了一个自身满足条件的串,那么贡献为2x-1;如果我们紧接着又遇到了一个满足条件的串,那么贡献就只有2(x-1)-1了。很明显,因为这两个串连接的情况被前面那个串处理过了所以要减掉。【这个细节卡了我好久。
所以我们把这些本身就满足要求的串扔出来单独处理,然后再单独考虑剩下的需要看拼接结果的串。
可以看代码理解一下:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define int long long
#define maxn 300005
using namespace std;
typedef long long ll;
int read() {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
return x * f;
}
int ans = 0, l = 1, cnt;
int n, maxx[maxn], minn[maxn], tot = 0;
signed main() {
n = read(); cnt = n;
for(int t, x, i = 1; i <= n; i++) {
t = read();
int tmp = 9999999; bool flag = false;
tot++; minn[tot] = tmp; maxx[tot] = 0;
while(t--) {
x = read();
if(x > tmp) flag = true;//如果前面有值比当前小,这个串自己就是满足条件的
tmp = min(tmp, x);
maxx[tot] = max(maxx[tot], x);//放进最大值和最小值
minn[tot] = min(minn[tot], x);
}
if(flag) tot--, ans += cnt + cnt - 1, cnt--;//如果满足条件,ans处理一下,注意cnt
}
sort(maxx + 1, maxx + 1 + tot);
sort(minn + 1, minn + 1 + tot);
for(int i = 1; i <= tot; i++) {//处理剩下的拼接的串
while(minn[l] < maxx[i] && l <= tot) l++;
ans += l - 1;
}
printf("%lld\n", ans);
return 0;
}
C题的博客后面也有。
迎评:)
——End——