2020暑期D2-G 思路+证明
主为自用,欢迎指正。
https://ac.nowcoder.com/acm/contest/5667/G
前置知识:
sort(add1,add2,cmp)。
bitset定义以及其常用函数。
二分查找函数:
lower_bound(起始地址,结束地址,要查找的数值) 返回的是数值 第一个 出现的位置。(pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。)
upper_bound(起始地址,结束地址,要查找的数值) 返回的是数值 最后一个 出现的位置。
binary_search(起始地址,结束地址,要查找的数值) 返回的是是否存在这么一个数,是一个bool值。
题意:
A数组长度为n,B数组长度为m,m=min(m,4000);若A中存在长度为m的连续子序列S,且S[i]>=B[i]。例,A={1,4,2,8,5,7};B={3,2,3};得S={4,2,8}、{8,5,7}(S数组与B数组同位置数字比较);
求多少个满足条件的子序列S。
应该有很多种解法,这里我只写题解的方法,可能略有不同,把握住整体思路即可。
思路:
1.写出所有A[i]的关于B的bitset(任意B[j],A[i]>=B[j],则bitset=1,else bitset=0),若bitsetA[i+j-1][j]==1(j∈{1,2,...,m}).则A数组的子序列S=(A[i],A[i+1],...,A[i+m-1])。
2.用这种思路找到实现方法后,首先我们需要得到bitset,其次实现bitsetA[i+j-1][j]==1(j∈{1,2,...,m})。
3.如何得到bitset呢,推荐不了解的同学先去学习一下STL中的bitset定义以及函数,这里根据题目简单讲一下核心,建立一个bitset首先确定位置,随后确定值。本题只有S[i]>=B[i]才置1;故我们先对原B数组排升序,对数据结构b按照b.x(值)排升序,得到所有满足条件的位置(核心1),后在位置上赋值1(核心2)。
在实现步骤3的过程中,我们发现经过排序后得到的所有bitset值实际上是所有能够满足条件的可能值,记为s[]。即,若存在S子序列满足条件,则其所有bitset值一定在s数组中;
G-1.JPG证明最多只有m中bitset能够S子序列中的值的bitset。
G-2.JPG解释为何要用升序找bitset。
理解了步骤1的同学得想到,S子序列的各个bitset值之间是存在着bitsetA[i+j-1][j]==1(j∈{1,2,...,m})的关系的,既然bitsetA[i+j-1]属于s数组,那么我们就不用再去求bitsetA啦;
直接在bt数组中找需要的bitset值,后把所有满足‘bitsetA[i+j-1][j]==1(j∈{1,2,...,m})’条件的S子序列找出来累加即可。
4.最后就是如何实现‘bitsetA[i+j-1][j]==1(j∈{1,2,...,m})’呢。首先我们需要确定A[i]是s数组中的哪一个bitset,也就是找到相应的位置,随后判断A[i]的bitset[j]是否等于1,如果成立则,i++&&j++,继续判断;但是这样将多了一个O(n)。
这时候让我们总结一下共识,若要存在一个S,则A[i]的bitset[j]==1,A[i+1]的bitset[j+1]==1,那么我们能否通过移位运算与与运算来代替遍历判断呢。即a=a&A[i]的bitset<<1,若a[j]==A[i]的bitset[j]==1;则a[j+1]==1,再运算a=a&A[i+1]的bitset<<1,则a[j+2]==1,就形成循环啦。
但是还有一个问题,如果中途中断了一次,那么循环就断了了,需要重新开始从ans[1]==1进行移位与与运算。但是我们又不想再写一个判断,所以再每次移位与与运算的时候再末尾都加一个1,即I=I.set(1);
代码步骤:
3.
sort(b+1, b + m+1, cmp); sort(B+1, B + m+1); for (int i = 1; i <= m; i++) { s[i] = s[i - 1]; s[i].set(b[i].pos); }
4.
ans.reset(); I.set(1); for (int i = 1; i <=n; i++) { pos = upper_bound(B+1,B+m+1, A[i]) - B - 1; ans = (((ans << 1) | I) & s[pos]); if (ans[m] == 1) cnt++; }
AC代码:
#define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<iostream> #include<bitset> #include<vector> #include<algorithm> using namespace std; bitset<40010>s[40010]; bitset<40010>ans, I; struct node { int pos, x; }b[40005]; int cmp(node a, node b) { return a.x < b.x; } int A[200005], B[40005]; int main() { int n, m; int cnt=0; int pos; scanf("%d %d", &n, &m); for (int i = 1; i <=n; i++) { scanf("%d", &A[i]); } for (int j = 1; j <=m; j++) { scanf("%d", &B[j]); b[j].pos = j; b[j].x = B[j]; } sort(b+1, b + m+1, cmp); sort(B+1, B + m+1); for (int i = 1; i <= m; i++) { s[i] = s[i - 1]; s[i].set(b[i].pos); } ans.reset(); I.set(1); for (int i = 1; i <=n; i++) { pos = upper_bound(B+1,B+m+1, A[i]) - B - 1; ans = (((ans << 1) | I) & s[pos]); if (ans[m] == 1) cnt++; } cout << cnt << endl; }