题目链接:http://codeforces.com/contest/567/problem/C
题意就是有n个数现在要让 ai aj ak 构成公比为K的等比数列(i < j < k);求有多少种组合方法;
我们可以对 a[i] 找 a[i]/k 和 a[i]*k ,设a[i]前面有 x个a[i]/k ;后面有y个 a[i]*k ;那么答案就是所有的x*y的和;由于数据比较大无法引用下标, 所以用map离散一下
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #include <vector> #include <map> #include <string> using namespace std; #define INF 0x3f3f3f3f #define met(a, b) memset(a, b, sizeof(a)) #define N 200005 typedef long long LL; int main() { int n; LL k, a[N]; while(scanf("%d %I64d", &n, &k)!=EOF) { map<LL, LL> mp1, mp2; for(int i=1; i<=n; i++) { scanf("%I64d", &a[i]); mp1[a[i]]++; } LL ans = 0; for(int i=n; i>=1; i--)///倒着来便于统计mp2[x]的个数,即倒着来的数的个数; { mp1[a[i]] --;///正着来的要减减; if(a[i]%k==0) ans += mp1[a[i]/k] * mp2[a[i]*k]; mp2[a[i]] ++; } printf("%I64d ", ans); } return 0; }
这是一个用二分写的,不用map离散化的代码;
LL a[maxn], b[maxn], l[maxn], r[maxn], n, m; LL bin_sreach (LL x) { LL high = m-1, low = 0; while (high >= low) { LL mid = (high + low) / 2; if (b[mid] == x) return mid; if (b[mid] < x) low = mid + 1; else high = mid -1; } return n; } int main () { LL k; while (scanf ("%I64d %I64d", &n, &k) != EOF) { for (LL i=0; i<n; i++) { scanf ("%I64d", &a[i]); b[i] = a[i]; } sort (b, b+n); m = unique(b, b+n) - b; memset (l, 0, sizeof(l)); memset (r, 0, sizeof(r)); for (LL i=0; i<n; i++) { LL x = bin_sreach(a[i]); l[x] ++; } __int64 ans = 0; for (LL i=n-1; i>=0; i--) { LL x, y, z; x = y = n; z = bin_sreach(a[i]); l[z] --; if (a[i] % k == 0) x = bin_sreach(a[i]/k); y = bin_sreach(a[i]*k); ans += l[x] * r[y]; r[z] ++; } printf ("%I64d ", ans); } return 0; }