直接按题意模拟计数即可,拿个单调栈和树状数组维护下...
题目不是求二元组的数量吗?i<j&&ai>=j&&aj>=i.
这是一个二维问题对吧,我们一维一维的解决.首先对于ai>n的直接取n就好,因为n一定是满足条件的.
然后我们令val和id,字面意思呐.我们都排序一下,对于原数组按val升序排序.当然在排序之前,我们需要存下它的值对吧,因为我们后面要枚举的.
后面枚举的话也是一个一个处理的,我们考虑枚举i=1到n.然后对于每个i判断下ai这个位子合法的数量,我们很容易知道,假如aj<i当前,那么这个j就不可能作为贡献,且以后也不会成为贡献.这个j就可以在树状数组中删除.然后对于其他的,直接query(a[i])即可.
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll N=2e5+5; struct vv{ ll id,val; }a[N]; bool cmp(vv x,vv y) { return x.val<y.val; } ll n,ca[N],sum[N],vis[N]; ll lowbit(ll x) { return x&(-x); } void add(ll pos,ll val) { while(pos<=n) { sum[pos]+=val; pos+=lowbit(pos); } } ll query(ll pos) { ll res=0; while(pos) { res+=sum[pos]; pos-=lowbit(pos); }return res; } int main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i].val); a[i].id=i; ca[i]=min(a[i].val,n); add(i,1); } sort(a+1,a+1+n,cmp); ll ans=0; for(int i=1,num=1;i<=n;i++) { if(!vis[i]) {add(i,-1);vis[i]=1;};//假如这个数没有被淘汰.就淘汰它. while(num<=n&&i>a[num].val) { if(!vis[a[num].id]) add(a[num].id,-1),vis[a[num].id]=1; num++; } ans+=query(ca[i]); } printf("%lld\n",ans); return 0; }