2 条题解
-
0
可算是给我来道水题了。
我这里有一个很玄学的思路,但是这题的思路应该都很玄学吧。
首先给 数组排个序。然后我们建立一个 数组, 表示最小的满足 的 。
对于每一个连续子序列的匹配,最优的匹配情况肯定是将 对应的区间倒序排序, 数组正序排序后一一匹配。如果这个都没法匹配那就肯定没有匹配方案了。
先记 为 在这个区间内出现的次数,由刚刚那个匹配方案得:
不然就无法匹配。
那么我们就考虑开棵线段树记录目前区间每个数的出现次数的前缀和就行了,一开始每个位置先减去对应的值即可。很明显这是一道区间修改维护区间最小值的题目,甚至我们只需要查询 节点的权值就行。
哦还有无法和 数组中的任意一个数匹配的数,这种直接记录这类数的个数,有的话就无法匹配。
#include<bits/stdc++.h> using namespace std; #define int long long const int N=2e5+10; int a[N],b[N],n,m,p,d[N],s[N]; #define lc(p) (p<<1) #define rc(p) (p<<1|1) struct SMTree { struct node{int l,r,mn,tag;}tr[N<<2]; void pushup(int p){tr[p].mn=min(tr[lc(p)].mn,tr[rc(p)].mn);} void pushdown(int p) { if(tr[p].tag) { tr[lc(p)].mn+=tr[p].tag; tr[rc(p)].mn+=tr[p].tag; tr[lc(p)].tag+=tr[p].tag; tr[rc(p)].tag+=tr[p].tag; tr[p].tag=0; } } void bt(int p,int l,int r) { tr[p]={l,r,0,0}; if(l==r){tr[p].mn=s[l]-l;return;} int mid=(l+r)>>1; bt(lc(p),l,mid);bt(rc(p),mid+1,r); pushup(p); } void add(int p,int l,int r,int k) { if(tr[p].l>r||tr[p].r<l)return ; if(l<=tr[p].l&&tr[p].r<=r) { tr[p].mn+=k; tr[p].tag+=k; return; } pushdown(p); add(lc(p),l,r,k);add(rc(p),l,r,k); pushup(p); } }tr; signed main() { cin>>n>>m>>p; for(int i=1;i<=m;i++)cin>>a[i]; for(int i=1;i<=n;i++)cin>>b[i]; sort(a+1,a+m+1); for(int i=1;i<=n;i++)b[i]=lower_bound(a+1,a+m+1,p-b[i])-a; for(int i=1;i<=m;i++)d[b[i]]++; for(int i=1;i<=m;i++)s[i]=s[i-1]+d[i]; int vsum=d[m+1]; tr.bt(1,1,m); int ans=(!vsum&&tr.tr[1].mn>=0); for(int i=m+1;i<=n;i++) { if(b[i-m]==m+1)vsum--; else tr.add(1,b[i-m],m,-1); if(b[i]==m+1)vsum++; else tr.add(1,b[i],m,1); ans+=(!vsum&&tr.tr[1].mn>=0); } cout<<ans; return 0; }
信息
- ID
- 10441
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 13
- 已通过
- 3
- 上传者