谷歌中国算法比赛解题报告 APAC2016E

Problem A. Lazy Spelling Bee

Problem B. Robot Rock Band

Problem C. Not So Random

Problem D. Sums of Sums


2016年的最后一场测试,参加人数看起来少了很多,可能要过年了吧,而且大多数人找到工作就没兴趣刷了……


1. 这个题很简单,对于每个字符,如果跟左边,右边都不同,左右两个字符也不同!!!!(这点很容易忽略)那就有3种情况,如果左右字符和自己都相同就是一种情况,其它都是两种情况。,每个字符都算一下后,乘起来就是答案


2. 又是一道先计算一遍中间结果存起来然后再找的题,把a^b^c^d=K变成a^b=K^d^c,然后遍历a,b村结果,再遍历d,c对每个K^d^c 查有没有对应的a^b就好了


3. 这个题又是一道一层一层滑动往下找的题,和2015B的那个酒杯题很像。因为按照题目的方法,产生重复数字的概率很高,所以不用担心存了太多数字,对当前层的每个数字都做一次三种操作,把新数字和对应概率存到下一层,具体思路一看代码就懂


4. 这道题大数据非常难,lz研究了好几个小时,具体做法相当复杂,最终的时间复杂度是O(n*logn*logn)。 具体做法分两个部分

1.比如 5,4,3,2,1 生成的数组是[1, 2, 3, 3, 4, 5, 5, 6, 7, 9, 9, 10, 12, 14, 15],如何快速求出第i个到第j个的和?

把 5,4,3,2,1 这么写

5                     5                  5

5 4                  9                  14

5 4 3              12                 26

5 4 3 2           14                 40

5 4 3 2 1        15                 55

如果我想求红色数字的和,应该怎么做? 这里蓝色的存的是每一行的和,绿色存的是自己合往上所有行的和

求红色部分的和,直接用绿色部分 55-26 得到29 再减去 两个蓝色第一行的5 就可以得出 19

这是第一个要注意的


第二个要注意的,是双重二分查找(你没看错,二分里面套二分)

同样还是把5,4,3,2,1这样写

5 4,3,2,1

4,3,2,1

3,2,1

2,1

1

比如我们想找第3个到第8个数字的和,那么第三个数字是谁?

我们不知道,但是我们可以二分找到它

假设第三个数字是10,那么对于那个三角矩阵

第一行5 小于10,5+4小于10,所以10前面有5,5+4

第二行4小于10,4+3小于10,4+3+2小于10,4+3+2+1等于10 注意等于号,说明我们要假设的数字是存在的,把等于的单独记录

第三行全都小于10

第四行,第五行同理,所以10前面共有 2+3+3+2+1 个小于10,一个等于10,所以10存在但不是第三个数字。那么二分上限取10,再继续找

注意如果一行的数字特别多,那么预先存一个sum数组如 [5,9,12,14,15]利用二分可以迅速定位要查找数字的位置


我们确定了第3个,第八个数字都是谁,也记录了这辆数字在每一层的index,接下来就是对每一层求和,注意在方法1中提到的如何求和,别去扫描数组一个一个加那样复杂度还是O(n2),就可以了


最后,一定一定要注意的是要用long long 存结果,别都做完了结果大数据在这里翻了船……

基本思路就到这里了,但是其实要注意的小细节里面还挺多的,尤其是index从0还是从1开始之类的,无比之烦,想锻炼自己可以做做试试


附上代码

#include <stdio.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <hash_map>
#include <hash_set>
#include <unordered_map>
#include <unordered_set>
#include <string.h>
#include <queue>
#include <list>
#include <iomanip>

using namespace std;

#define ll long long
#define uint unsigned int


class PA
{
public:
	PA(){}
	string words;
	int MODE = 1e9 + 7;

	void SingleProcess(ofstream& fout)
	{
		vector<int> nums(words.length(),1);
		if (words.length() == 1)
		{
			fout << 1;
			return;
		}
		for (int i = 0; i < words.length(); i++)
		{
			if (i == 0&&i<words.length()-1)
			{
				if (words[i] != words[i + 1]) nums[i] = 2;
			}
			else if (i == words.length() - 1 && i>0)
			{
				if (words[i] != words[i - 1]) nums[i] = 2;
			}
			else
			{
				if (words[i] != words[i + 1] && words[i] != words[i - 1]&&words[i+1]!=words[i-1]) nums[i] = 3;
				else if (words[i] == words[i + 1] && words[i] == words[i - 1]) nums[i] = 1;
				else nums[i] = 2;
			}
		}
		ll ret = 1;
		for (int i = 0; i < nums.size(); i++)
		{
			ret *= nums[i];
			ret %= MODE;
		}
		fout << ret;
	}

	void run()
	{
		FILE* fp = freopen("in.txt", "r", stdin);
		ofstream fout("out.txt");
		int Cases = 0;
		scanf("%d", &Cases);
		for (int time = 0; time < Cases; time++)
		{
			char ch[1024];
			cin >> ch;
			words = ch;

			fout << "Case #" << (time + 1) << ": ";
			SingleProcess(fout);
			fout << endl;
			std::cout << time << endl;
		}
		fclose(fp);
		fout.close();
	}
};

class PB
{
public:
	PB(){}
	int N, K;
	vector<int> A, B, C, D;
	
	void SingleProcess(ofstream& fout)
	{
		map<int,int> abmap;
		map<int, int>::iterator iter;
		for (int i = 0; i < N; i++)
		{
			for (int j = 0; j < N; j++)
			{
				abmap[A[i] ^ B[j]]++;
			}
		}

		ll count = 0;
		for (int i = 0; i < N; i++)
		{
			int t = K^D[i];
			for (int j = 0; j < N; j++)
			{
				iter = abmap.find(t^C[j]);
				if (iter != abmap.end()) count += iter->second;
			}
		}

		fout << count;
	}

	void run()
	{
		FILE* fp = freopen("in.txt", "r", stdin);
		ofstream fout("out.txt");
		int Cases = 0;
		scanf("%d", &Cases);
		for (int time = 0; time < Cases; time++)
		{
			cin >> N >> K;
			A.resize(N);
			B.resize(N);
			C.resize(N);
			D.resize(N);
			for (int i = 0; i < N; i++)
			{
				cin >> A[i];
			}
			for (int i = 0; i < N; i++)
			{
				cin >> B[i];
			}
			for (int i = 0; i < N; i++)
			{
				cin >> C[i];
			}
			for (int i = 0; i < N; i++)
			{
				cin >> D[i];
			}

			fout << "Case #" << (time + 1) << ": ";
			SingleProcess(fout);
			fout << endl;
			std::cout << time << endl;
		}
		fclose(fp);
		fout.close();
	}
};

class PC
{
public:
	PC(){}
	int N, X, K, A, B, C;

	void SingleProcess(ofstream& fout)
	{
		map<int, double> level1, level2;
		map<int, double>* currLevel, *nextLevel;

		double pa = A / 100.0;
		double pb = B / 100.0;
		double pc = C / 100.0;
		level1[X] = 1;
		currLevel = &level1;
		nextLevel = &level2;
		for (int i = 0; i < N; i++)
		{
			nextLevel->clear();
			for (map<int, double>::iterator iter = currLevel->begin(); iter != currLevel->end(); iter++)
			{
				(*nextLevel)[iter->first&K] += iter->second*pa;
				(*nextLevel)[iter->first|K] += iter->second*pb;
				(*nextLevel)[iter->first^K] += iter->second*pc;
			}
			swap(nextLevel, currLevel);
		}
		double ret = 0;
		for (map<int, double>::iterator iter = currLevel->begin(); iter != currLevel->end(); iter++)
		{
			ret += iter->first*iter->second;
		}
		fout << setprecision(10) << fixed << ret;
	}

	void run()
	{
		FILE* fp = freopen("in.txt", "r", stdin);
		ofstream fout("out.txt");
		int Cases = 0;
		scanf("%d", &Cases);
		for (int time = 0; time < Cases; time++)
		{
			cin>>N>>X>>K>>A>>B>>C;


			fout << "Case #" << (time + 1) << ": ";
			SingleProcess(fout);
			fout << endl;
			std::cout << time << endl;
		}
		fclose(fp);
		fout.close();
	}
};

class PD
{
public:
	PD(){}
	int N,Q;
	vector<ll> initArray;
	vector<pair<ll, ll>> queries;
	vector<ll> sumValue, sumsumValue;

	void findBound(vector<pair<ll, ll>>& bound, ll index,ll& target,ll& more)
	{
		ll lower = 0;
		ll upper = sumValue.back() + 1;
		target = (lower + upper) / 2;
		while (true)
		{
			ll total = 0;
			ll equal = 0;
			for (int i = 0; i < N; i++)
			{
				if (target < initArray[i])
				{
					bound[i].first = bound[i].second = 0;
					continue;
				}
				else if (target>=sumValue[N] - sumValue[i])
				{
					bound[i].first = N - i;
					if (target == sumValue[N] - sumValue[i]) bound[i].second = 1;
					else bound[i].second = 0;

					total += bound[i].first;
					equal += bound[i].second;
					if (total - equal > index) break;
				}
				else
				{
					ll left = i;
					ll right = N;
					ll mid = (left + right) / 2;
					while (left != right - 1)
					{
						if (sumValue[mid] - sumValue[i] > target) right = mid;
						else left = mid;
						mid = (left + right) / 2;
					}
					bound[i].first = left-i;
					if (sumValue[left] - sumValue[i] == target) bound[i].second = 1;
					else bound[i].second = 0;
					total += bound[i].first;
					equal += bound[i].second;
					if (total - equal > index) break;
				}
			}


			if (equal > 0 && total - equal <= index&&total > index)
			{
				more = equal - (total - index);
				return;
			}
			if (total>index)
			{
				upper = target;
				target = (lower + upper) / 2;
			}
			else
			{
				lower = target;
				target = (lower + upper) / 2;
			}
		}
		
		
	}

	void SingleProcess(ofstream& fout)
	{
		sumValue[0] = sumsumValue[0] = 0;
		for (int i = 0; i < initArray.size(); i++)
		{
			sumValue[i+1] = sumValue[i] + initArray[i];
			sumsumValue[i+1] = sumsumValue[i] + sumValue[i+1];
		}

		vector<pair<ll, ll>> leftBound(N), rightBound(N);
		ll leftTarget, rightTarget, leftMore, rightMore;
		for (int i = 0; i < Q; i++)
		{
			findBound(leftBound,queries[i].first-1,leftTarget,leftMore);
			findBound(rightBound, queries[i].second-1,rightTarget,rightMore);
			ll sum = 0;
			for (int j = 0; j < N; j++)
			{
				ll l = j + leftBound[j].first - leftBound[j].second;
				ll r = j + rightBound[j].first - rightBound[j].second;
				sum += sumsumValue[r] - sumsumValue[l] - sumValue[j] * (r - l);
			}
			sum -= leftTarget*leftMore;
			sum += rightTarget*(rightMore+1); //注意算上自己
			fout << "\n" << sum;
		}
	}

	void run()
	{
		FILE* fp = freopen("in.txt", "r", stdin);
		ofstream fout("out.txt");
		int Cases = 0;
		scanf("%d", &Cases);
		for (int time = 0; time < Cases; time++)
		{
			cin>>N>>Q;
			initArray.resize(N);
			sumValue.resize(N + 1);
			sumsumValue.resize(N + 1);
			for (int i = 0; i < N; i++)
			{
				cin >> initArray[i];
			}
			queries.resize(Q);
			for (int i = 0; i < Q; i++)
			{
				cin >> queries[i].first >> queries[i].second;
			}

			fout << "Case #" << (time + 1) << ": ";
			SingleProcess(fout);
			fout << endl;
			std::cout << time << endl;
		}
		fclose(fp);
		fout.close();
	}
};





int main()
{
	//PA p;
	//PB p;
	//PC p;
	PD p;
	p.run();

	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值