Codeforces Round #Pi (Div. 2) C. Geometric Progression
原题: http://codeforces.com/contest/567/problem/C
题目大意: 给一个n大小数组, 问其中的子序列(非连续)能组成多少个已p为公比的等比序列, 且长度为3.
分析: 这题卡了好久, 我用找等差数列的方法改的. 后来总是过不了test. 可是怎么看我的是O(nlgn)的复杂度, 所以过不了大的test case 肯定是有O(n)的. 于是开始想啊想啊….最后想到了是用等比中项的性质.
首先上一个过不了的code:
public void solve(int testNumber, InputReader in, OutputWriter out) { int n = in.readInt(); int p = in.readInt(); IntPair[] nums = new IntPair[n]; for (int i = 0; i < nums.length; i++) { nums[i] = new IntPair(in.readInt(),i); } Arrays.sort(nums); int count = 0; for (int i = 1; i < nums.length-1; i++) { int j = i - 1; int k = i + 1; while (j >= 0 && k < nums.length) { if (nums[j].first * nums[k].first > nums[i].first*nums[i].first) j--; else if (nums[j].first * nums[k].first < nums[i].first*nums[i].first) k++; else { if ((nums[i].first/nums[j].first) != p && (nums[k].first/nums[i].first) != p) continue; count++; while (j > 0 && nums[j].first == nums[j - 1].first && nums[j].second < nums[i].second && nums[i].second <nums[k].second) { j--; count++; } while (k < nums.length - 1 && nums[k].first == nums[k + 1].first && nums[j].second < nums[i].second && nums[i].second <nums[k].second) { k++; count++; } j--; k++; } } } out.print(count); } }
最后看了一下答案, 发现是用两个set保存当前数字为等比中项的前后序列, 然后记录一下相同项的个数. 第二次扫描的时候, 如果当前数字能整除公比, 那么找到j,i,k的个数,相乘就是答案. 这里注意要用long存. 难怪我test老挂
答案code:
public void solve(int testNumber, InputReader in, OutputWriter out) { int n = in.readInt(); int p = in.readInt(); Map<Long,Long> l = new HashMap<>(); Map<Long,Long> r = new HashMap<>(); long res = 0; long[] nums = new long[n]; for (int i = 0; i < n; i++) { nums[i] = in.readLong(); if (r.containsKey(nums[i])) r.put(nums[i], r.get(nums[i])+1); else r.put(nums[i],1l); l.put(nums[i],0l); } for (int i = 0; i < n; i++) { r.put(nums[i],r.get(nums[i])-1l); if (nums[i] % p == 0){ if (l.containsKey(nums[i]/p) && r.containsKey(nums[i]*p)) res += l.get(nums[i]/p) * r.get(nums[i]*p); } l.put(nums[i],l.get(nums[i])+1l); } out.print(res); }
Leave A Comment