C题:
一期思路:我们发现如果x,y满足条件,那么{x,-y} {-x,y} {-x,-y}也满足条件。那么我们可以只讨论|x| |y|是否满足条件,如果满足条件,那么对ans的贡献是|x|出现次数*|y|出现次数。
于是引申出用二分查找满足条件的值的最靠后的位置,用map保存出现的次数,因为你会发现元素的范围在-10亿到10亿,不能开线性数组来保存出现次数。
查找到最靠后的位置之后,
for(j=i+1;j<=ans_pos;++j) ans = ans + cnt[base]*cnt[ v[j] ];
但是这样的坏处是
(1)使用了map,map需要查找时间
(2)每个都要遍历一遍,复杂度到了O(n^2)。
(3)容易忽略绝对值相等的情况
因为一个-x和一个x是能满足条件的,而这个公式很显式的把这种情况排除了,思路就被带偏了。
综上,即使我解决了(3),if(cnt[base]==2) ++ans;
还是会因为复杂度到了O(n^2)而超时,那么这时候题解的思路就很好了,压入的是所有的绝对值,这样不仅节约时间,还保证了能考虑到绝对值相等也能满足题意的情况。
思路正确但是TLE的代码:
#include <bits/stdc++.h> #define pt printf #define sc scanf #define maxn 200005 #define ull unsigned long long #define inf 0x3f3f3f3f using namespace std; int N; int a[maxn]; vector<int> v; map<int,int> cnt; int can(int where,int base) { int val = v[where] ; if(val%2==0) { if(base>=val/2) return 1; return 0; } else { if(base> val/2) return 1; return 0; } } int main() { sc("%d",&N); int i,j,x; for(i=0;i<N;++i) sc("%d",&a[i]); for(i=0;i<N;++i) { x = abs(a[i]); if(cnt.find(x)==cnt.end()) { cnt[x]=1; v.push_back(x); } else ++cnt[x]; } sort(v.begin(), v.end()); int len = v.size(); // for(i=0;i<len;++i) pt("cnt[v[i]]=%d ",cnt[v[i]]); // pt(" "); ull ans = 0; //假设大的数是b,小的数是a //如果b是偶数,如果a大于等于b的一半那就可以 //如果b是奇数,如果a大于b的一半那就可以 for(i=0;i<len;++i) { // pt("i=%d ",i); int base = v[i]; int l = i+1, r = len - 1, ans_pos = i ; //pt("base=%d ,l=%d ,r=%d ,ans_pos=%d ",base,l,r,ans_pos); while(l<=r) { int mid = (l+r)>>1; int status = can(mid,base); if(status==1) { ans_pos = mid; l = mid + 1; } else { r = mid - 1; } } for(j=i+1;j<=ans_pos;++j) { ans = ans + cnt[base]*cnt[ v[j] ]; } if(cnt[base]==2) ++ans; } pt("%llu ",ans); return 0; }
AC的代码:满足条件的函数我分了奇偶讨论,但是只要 小的数*2>=大的数 就可以了。
#include <bits/stdc++.h> #define pt printf #define sc scanf #define maxn 200005 #define ull unsigned long long #define inf 0x3f3f3f3f using namespace std; int N; int a[maxn]; vector<int> v; int can(int where,int base) { int val = v[where] ; if(val%2==0) { if(base>=val/2) return 1; return 0; } else { if(base> val/2) return 1; return 0; } } int main() { sc("%d",&N); int i,j,x; for(i=0;i<N;++i) sc("%d",&a[i]); for(i=0;i<N;++i) { x = abs(a[i]); v.push_back(x); } sort(v.begin(), v.end()); int len = N; // for(i=0;i<len;++i) pt("cnt[v[i]]=%d ",cnt[v[i]]); // pt(" "); ull ans = 0; //假设大的数是b,小的数是a //如果b是偶数,如果a大于等于b的一半那就可以 //如果b是奇数,如果a大于b的一半那就可以 for(i=0;i<len;++i) { // pt("i=%d ",i); int base = v[i]; int l = i+1, r = len - 1, ans_pos = i ; //pt("base=%d ,l=%d ,r=%d ,ans_pos=%d ",base,l,r,ans_pos); while(l<=r) { int mid = (l+r)>>1; int status = can(mid,base); if(status==1) { ans_pos = mid; l = mid + 1; } else { r = mid - 1; } } ans += (ans_pos-i); } pt("%llu ",ans); return 0; }