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

Problem A. Travel

Problem B. gWheels

Problem C. gNumbers

Problem D. Albocede DNA


1. 这道题,根据题目的数据,如果能早到一个点,一定不比晚到差,所以本质上还是一个DFS,就是有点麻烦,但比起APAC2015C的那道metro题要简单多了。把该定义的定义好,条理搞清晰些很容易过。


2. 这道题,典型的先计算一遍所有 p,t的比例组合,存进map里,然后O(n2)扫描e数组,对任意两个数字,看看能不能组成的齿轮组能不能在p,t组合中找到,找到就输出YES,退出,如果全部扫描完都找不到yes,就输出no。

实现后发现大数据有些慢,看了大神的做法,也都是一样,所以这应该是最优的……


3. 博弈问题,一般来说,博弈问题的经典解法就是,如果我能找到一个获胜点,我就获胜,如果我一个都找不到,我就失败,但因为每次都两个人来回选,所以如果对方失败,我就获胜,对方获胜,我就失败。 也是就说,假设DFS会返回true,false,那么如果第k层返回false,对于第k-1层就是true……大概就是这个意思,DFS的每一层都要把下一层的结果反一下


针对这个题,同样DFS,对每个人,先查当前数字会不会输,会输就直接返回,否则,遍历这个数字的质数因子,去查生成的新数字,对方会不会输,如果对方会输,则返回赢,如果查完了所有的对方都不会输,则返回自己会输


大数据还要注意先生成一个质数库,为了方便我用set存了,注意虽然题目数据上限10的15次方,但只要找3.2*(10**7)(比平方根大就行,32000000写着方便……)以内的质数即可。暴力生成这些质数也就几秒钟的事


4.这个题很难很麻烦

大神的DP我还没来得及看,本人的思想是将ab组成pair, cd 组成pair, 然后对每个ab pair, 去找后面所有能组合的 cd pair。 具体思路如下:

先开一个数组,对每个对应位置是a的,记录以这个a开头有多少种DNA

对每个对应位置是d的,找后面所有的a,因为d可以连任意一个a,所以存下d总共可以连多少种情况,把每个a存的数量加起来

对每个对应位置是c的,找后面任意一个c,然后以这两个c为起点终点,计算有多少种c的情况(需要用到预选生成的组合库),以这个c为终点找d,记录每个cd pair有多少种

对每个对应位置是b的,把从这个b开始的后面所有c的每种情况都加过来,方便a找b时直接用(不用再加了,这是一步重要减枝)

对每个对应位置是a的,找到后面任意一个a,这两个a作为起点终点,然后在找后面的b,对每个ab pair, 找这个b 存的 cd pair 有没有对应的, 最后a记录所有从这个a开始有多少DFA

从后往前扫描:执行上面的步骤

最后,小数据可以轻松过,但是大数据要处理超时……再做一个减枝,如果ab,cdpair 任意一个数字超过250 就直接舍弃,数据量减了一半,时间上勉勉强强够

至于如何更快的解,请下大神的代码看……我没仔细研究,但基本思想看起来差不多 


最后 附上代码

#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
#ifndef INT_MAX
#define INT_MAX 0x7fffffff
#endif

class PA
{
public:
	PA(){}
	int M, N, K;
	struct Road
	{
		int id;
		int from;
		int to;
		vector<int> timesTaken;
		Road(){ id = from = to = 0; }
		int getUsedTime(int currTime)
		{
			return timesTaken[currTime%24];
		}
		int getEndCity(int from_)
		{
			if (from_ == from) return to;
			else return from;
		}
	};

	struct City
	{
		int id;
		vector<int> roadId;
		City(){ id = 0; }
	};
	vector<Road> roads;
	vector<City> cities;
	vector<pair<int, int>> queries;

	vector<vector<int>> visited;

	void DFS(int start, int time, int end,int begin)
	{
		if (start == end)
		{
			visited[begin][start] = min(visited[begin][start], time);
			return;
		}

		if (visited[begin][start] <= time) return;

		visited[begin][start] = time;
		for (int i = 0; i < cities[start].roadId.size(); i++)
		{
			int roadid = cities[start].roadId[i];
			int to = roads[roadid].getEndCity(start);
			DFS(to, roads[roadid].getUsedTime(time) + time, end,begin);
		}
	}

	void SingleProcess(ofstream& fout)
	{
	
		visited.clear();
		visited.resize(24,vector<int>(N, INT_MAX));
		for (int i = 0; i < 24; i++)
		{
			DFS(0, i, INT_MAX,i);
		}
		
		for (int i = 0; i < queries.size(); i++)
		{
			if (visited[queries[i].second%24][queries[i].first] == INT_MAX)
			{
				fout << -1 << " ";
			}
			else fout << visited[queries[i].second % 24][queries[i].first] - (queries[i].second % 24) << " ";
		}
	}

	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 >> M >> K;
			cities.clear();
			cities.resize(N);
			roads.clear();
			roads.resize(M);
			queries.clear();
			queries.resize(K);
			for (int i = 0; i < N; i++)
			{
				cities[i].id = i;
			}
			for (int i = 0; i < M; i++)
			{
				roads[i].id = i;
				cin >> roads[i].from >> roads[i].to;
				roads[i].from--;
				roads[i].to--;
				cities[roads[i].from].roadId.push_back(i);
				cities[roads[i].to].roadId.push_back(i);
				roads[i].timesTaken.resize(24, 0);
				for (int j = 0; j < 24; j++)
				{
					cin >> roads[i].timesTaken[j];
				}
			}
			for (int i = 0; i < K; i++)
			{
				cin >> queries[i].first >> queries[i].second;
				queries[i].first--;
				queries[i].second;
			}

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

class PB
{
public:
	PB(){}
	int NP, NE,NT;
	int M;

	ll GCD(ll v1, ll v2)
	{
		while (v1)
		{
			ll temp = v1;
			v1 = v2%v1;
			v2 = temp;
		}
		return v2;
	}
	set<pair<ll,ll>> eeset, ptset;
	vector<ll> pvec, evec, tvec;
	vector<pair<ll, ll>> queries;

	void SingleProcess(ofstream& fout)
	{
		ptset.clear();

		for (int i = 0; i < pvec.size(); i++)
		{
			for (int j = 0; j < tvec.size(); j++)
			{
				int g = GCD(pvec[i], tvec[j]);
				ll t1 = pvec[i] / g;
				ll t2 = tvec[j] / g;
				ptset.insert(make_pair(t1,t2));
			}
		}

		for (int i = 0; i < queries.size(); i++)
		{
			bool findone = false;
			for (int e1 = 0; e1 < NE;e1++)
			{
				for (int e2 = 0; e2 < NE;e2++)
				{
					if (e1 == e2) continue;

					ll t1 = evec[e1]*queries[i].first;
					ll t2 = evec[e2]*queries[i].second;
					ll g = GCD(t1, t2);
					t1 /= g;
					t2 /= g;
					if (ptset.find(make_pair(t1,t2))!=ptset.end())
					{
						fout << endl << "Yes";
						findone = true;
						break;
					}
				}
				if (findone) break;
				
			}
			if (!findone)
			{
				fout << endl << "No";
			}
		}

	}

	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 >> NP >> NE >> NT;
			pvec.resize(NP);
			evec.resize(NE);
			tvec.resize(NT);
			for (int i = 0; i < NP; i++)
			{
				cin >> pvec[i];
			}
			for (int i = 0; i < NE; i++)
			{
				cin >> evec[i];
			}
			for (int i = 0; i < NT; i++)
			{
				cin >> tvec[i];
			}
			cin >> M;
			queries.resize(M);
			for (int i = 0; i < M; i++)
			{
				cin >> queries[i].first >> queries[i].second;
			}


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


class PC
{
public:
	PC(){}
	ll N;
	vector<ll> primes;
	set<ll> primeSet;
	map<ll, bool> winMap;
	void predefine()
	{
		ll UPPER = 32000000;
		for (int i = 2; i < UPPER; i++)
		{
			bool findone = false;
			for (int j = 0; j < primes.size(); j++)
			{
				if (primes[j] * primes[j]>i) break;
				if (i%primes[j] == 0)
				{
					findone = true;
					break;
				}
			}
			if (!findone)
			{
				primes.push_back(i);
				primeSet.insert(i);
			}
		}
	}

	bool isGNumber(ll num)
	{
		ll ss = 0;
		while (num > 0)
		{
			ss += num % 10;
			num = num / 10;
		}

		if (ss == 1) return true;

		for (int i = 0; i < primes.size(); i++)
		{
			if (primes[i]>ss) return false;
			if (primes[i] == ss) return true;
		}
		return false;
	}

	bool DFS(ll num)
	{
		if (winMap.find(num) != winMap.end()) return winMap[num];
		if (isGNumber(num)) return false;
		if (primeSet.find(num) != primeSet.end()) return true;
		
		ll upper = sqrt(num) + 1;
		ll temp = num;
		for (int i = 0; i < primes.size(); i++)
		{
			if (primes[i]>=upper) break;
			if (temp%primes[i] == 0)
			{
				ll t1 = primes[i];
				while (temp%t1 == 0) t1 *= primes[i];
				t1 /= primes[i];
				temp /= t1;
				if (DFS(num/t1) == false)
				{
					winMap[num] = true;
					return true;
				}
			}
		}
		//留下来的也是质数,不是1就测试num/temp
		if (temp > 1)
		{
			if (DFS(num / temp) == false)
			{
				winMap[num] = true;
				return true;
			}
		}
		winMap[num] = false;
		return false;
	}


	void SingleProcess(ofstream& fout)
	{
		//winMap.clear();
		if (DFS(N))
		{
			fout << "Laurence";
		}
		else
		{
			fout << "Seymour";
		}
	}

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


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

class PD
{
public:
	PD(){}
	string S;
	ll MODE = 1e9 + 7;
	vector<vector<ll>> C;
	void preDefine()
	{
		C.resize(501, vector<ll>(501, 0));
		for (int i = 0; i < 501; i++)
		{
			for (int j = 0; j <= i; j++)
			{
				if (j == 0) C[j][i] = 1;
				else if (i == j) C[j][i] = 1;
				else C[j][i] = C[j - 1][i - 1] + C[j][i-1];
				C[j][i] %= MODE;
			}
		}
	}
	struct SingleWord
	{
		char word;
		ll num;
		//map<pair<ll, ll>, ll> pairs;
		vector<vector<ll>> pairs;
		SingleWord(){ word = '0'; num = 0;}
	};
	vector<SingleWord> wordvec;

	void SingleProcess(ofstream& fout)
	{
		wordvec.clear();
		wordvec.resize(S.length());
		for (int i = S.length()-1; i>=0; i--)
		{
			if (S[i] == 'd')
			{
				wordvec[i].word = 'd';
				wordvec[i].num = 1;
				for (int j = i + 1; j < S.length(); j++)
				{
					if (S[j] == 'a') wordvec[i].num += wordvec[j].num;
				}
				wordvec[i].num %= MODE;
			}
			else if (S[i] == 'c')
			{
				wordvec[i].pairs.clear();
				wordvec[i].pairs.resize(251, vector<ll>(251, 0));
				int ct = 0;
				int dt = 0;
				for (int j = i + 1; j < S.length(); j++)
				{
					if (S[j] == 'c') ct++;
					else if (S[j] == 'd')
					{
						//以j为起点'd';
						dt = 0;
						//先算以j为终点的cd,pair
						for (int kc = min(ct,249); kc >= 0; kc--)
						{
							ll t = C[kc][ct] * wordvec[j].num%MODE;
							wordvec[i].pairs[kc+1][1] += t;
						}

						//再算以j后面的k为终点的cd,pair
						for (int k = j + 1; k < S.length(); k++)
						{
							if (S[k] == 'd') //以这个'd'为终点
							{
								for (int kc = min(ct,249); kc >= 0; kc--)
								{
									for (int kd = min(dt,248); kd >= 0; kd--)
									{
										ll t = C[kc][ct] * C[kd][dt] % MODE *wordvec[k].num%MODE;
										wordvec[i].pairs[kc + 1][kd+2] += t;
									}
								}
								dt++;
							}
						}
					}
				}
			}
			else if (S[i] == 'b')
			{
				wordvec[i].pairs.clear();
				wordvec[i].pairs.resize(251, vector<ll>(251, 0));
				//每个b点把后面的cdpair 综合起来,这样a过来查到b就不用往后查了
				for (int j = i + 1; j < S.length(); j++)
				{
					if (S[j] == 'c')
					{
						for (int t1 = 0; t1 < 251;t1++)
						{
							for (int t2 = 0; t2 < 251; t2++)
							{
								wordvec[i].pairs[t1][t2] += wordvec[j].pairs[t1][t2];
								wordvec[i].pairs[t1][t2] %= MODE;
							}
						}
					}
				}


			}
			else if (S[i] == 'a')
			{
				//查找所有以这个a为起点的abpair;
				int ta = 0;
				for (int j = i + 1; j < S.length(); j++)
				{
					if (S[j] == 'a')
					{
						ta++;
					}
					else if (S[j] == 'b')
					{
						//以这个b为起点
						//先算以这个b为终点
						int tb = 0;
						ll tot = 0;
						for (int ka = min(ta,249); ka >= 0; ka--)
						{
							//找后面所有能匹配的cdpair
							tot += wordvec[j].pairs[ka + 1][1] * C[ka][ta] % MODE;
						}
						wordvec[i].num += tot;

						//再算以这个b为起点,以后面的b为终点
						tb = 0;
						for (int k = j + 1; k < S.length(); k++)
						{
							if (S[k] == 'b')
							{
								tot = 0;
								for (int ka = min(ta,249); ka >= 0; ka--)
								{
									for (int kb = min(tb,248); kb >= 0; kb--)
									{
										tot += C[kb][tb] * C[ka][ta] % MODE*wordvec[k].pairs[ka+1][kb+2]%MODE;
									}
								}
								wordvec[i].num += tot;
								wordvec[i].num %= MODE;
								tb++;
							}
						}
					}
				}
			}

		}

		ll total = 0;
		for (int i = 0; i < S.length(); i++)
		{
			if (S[i] == 'a')
			{
				total += wordvec[i].num;
				total %= MODE;
			}
		}
		fout << total;
		return;
	}

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


			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、付费专栏及课程。

余额充值