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

Problem A. Password Attacker

Problem B. New Years Eve

Problem C. Card Game

Problem D. Parentheses Order


这次比赛的题都是动态规划题,对练习动态规划很有帮助……


1. 这个题首先如果M =1 那么不管N等于多少,都只有1种可能,即C[1][1]=1,C[1][2]=1,C[1][3]=1,...,C[1][100]=1 题目中N最大100

对于每一个M,N,比如M=3,N=4, 和 M=2, N=3 和 M=3,N=3 有什么关系呢?

首先看 (3,4)跟(3,3)的关系,我们规定所有的位置都必须往后多(避免重复),因为多了一个位置,所以多的位置可以放3个数字的任意一个,即(3,4)=(3,3)*3

再看(3,4)根(2,3)的关系,因为多了一个数字和位置,所以多的数字只能放多出来的位置,但要注意,多出来的数字可以跟任意一个以填写的数字交换,所以 (3,4)=(2,3)*3

综合,没有其它情况了。

所以 C[i][j]=C[i][j-1]*i+C[i-1][j-1]*i; 注意,如果i>j-1 那么不能计算C[i][j-1], 我们可以偷个懒,把所有 C[i][j]中i比j大的设为0

此题得解


2.

这一题,设置两个level,然后滑动数组(是这么叫的么,俺没好好学过算法。。。为了找工作才刷的题。。。),注意找到下一层level和当前level的关系,然后一层一层滑过去,就可以解题了,其实挺简单的……

下一层每个酒杯的酒量,等于找到上一层谁能传给它酒,然后上一层这个对应的杯子酒量减去250,如果大于0,再除以3传给下一层这个杯子。


3.

这个题我做不出来T_T , 小数据很简单,贪心即可,碰到3个连着的就消除,但是大数据不能这样贪心,看了高手们的解法,大数据贪心的思想是,每个数字都尽量找能连得最远的消除!!!

举例

数组:1 2 3 4 2 3 4 5 3

位置:0 1 2 3 4 5 6 7 8

那么对于1,能连的最远的是4号位的2,8号位的3

下面求怎么找连得最远,具体做法如下

先扫第一遍,找出所有能连得

这样应该是,从位置看

0-1-2  1-2-3  4-5-6 5-6-7

下面扫第二遍,注意0号位发现 1-2-3 后,它就可以跳过1-2-3 尝试 0-4-5,0-4-5 比0-1-2远,所以0号位存0-4-5

注意扫到 2-3-?的时候 发现4-5-6连着,所以尝试7,发现 2-3-7,所以2号位存2-3-7

0-4-5 1-2-3 2-3-7 4-5-6 5-6-7

再扫第三遍,0-4-?发现5-6-7连着,所以尝试8,发现0-4-8

0-4-8 ……

扫到没有人愿意更新自己为止,那么再从头到尾查一遍,注意可能出现

0-4-8  10-20-30 ...这样的

所以要全部扫一遍,找出没有被跳过的数字,输出即可解题



4. 这道题其实不难,但思路不好想,最近的一次leetcode的比赛smarking contest 1的最后一题跟它很像。我也是做了那道题(当然比赛时没做出来,后来看了高手们的解法……)才能做出这道题

这题的思想还是动归,首先所有的正确的左右括号都必须符合每一步左括号数都大于等于右括号数。

把这个思路翻一下,每次剩下的 左括号 数量 必须 小于等于 剩下的 右括号 数量

接下来就可以动归了,题目中N<=100 ,所以定义C[101][101], 第一维表示剩下几个左括号,第二维表示剩下几个右括号

那么首先 C[0][x] x任意值,都是1

比如 对于 C[3][4] 那么我们下一步可以用一个左括号,也可以用一个右括号,所以C[3][4]的valid组合的数量是

C[3][4]=C[2][4]+C[3][3]

即C[i][j]=C[i-1][j]+C[i][j-1]

偷个懒,如果C[i][j]中i>j,则C[i][j]=0; 这样我们不用可以去if else 递归中j-1<i的情况

得到了这个表后,比如题目中的3,4

C[3][3]=6 6>4 所以4号是存在的

C[2][3]=6 6>4 所以第一个是(

C[1][3]=3 3<=4 所以第二个是 )同时更新序号4变为4-3=1,下一步找C[2][2]这一枝(C[1][3]的兄弟枝)

C[2][2]=3 3>1 所以第三个是(

C[1][2]=2 2>1 所以第四个是(

C[0][2]=1 1<=1 所以第五个是) 更新序号变为0

C[0][1]=1 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
class CA
{
public:
	CA(){}
	int M, N;
	int MODE = 1e9 + 7;
	ll C[101][101];

	void generateC()
	{
		memset(C, 0, 101 * 101 * sizeof(ll));
		for (int i = 1; i < 101; i++)
		{
			int m = i;
			for (int j = i; j < 101; j++)
			{
				if (i == 1) C[i][j] = 1;
				else if (j == i) C[i][j] = C[i - 1][j - 1] * i%MODE;
				else {
					C[i][j] = C[i][j - 1] * i + C[i - 1][j - 1] * i;
					C[i][j] %= MODE;
				}
				
			}
		}
	}

	ll SingleProcess()
	{
		return C[M][N];
	}

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

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

class CB
{
public:
	CB(){}
	int B, L, N;
	vector<vector<double>> level1;
	vector<vector<double>> level2;

	double SingleProcess()
	{
		vector<vector<double>> *currLevel, *nextLevel;
		currLevel = &level1;
		nextLevel = &level2;
		(*currLevel)[1][1] = B*750.0;
		for (int l = 2; l <= L; l++)
		{
			for (int r = 1; r <= l; r++)
			{
				for (int c = 1; c <= r; c++)
				{
					(*nextLevel)[r][c] = (*currLevel)[r][c] > 250 ? ((*currLevel)[r][c] - 250.0) / 3 : 0;
					(*nextLevel)[r][c] += (*currLevel)[r-1][c-1] > 250 ? ((*currLevel)[r-1][c-1] - 250.0) / 3 : 0;
					(*nextLevel)[r][c] += (*currLevel)[r-1][c] > 250 ? ((*currLevel)[r-1][c] - 250.0) / 3 : 0;
				}
			}
			swap(currLevel, nextLevel);
		}
		for (int i = 1; i < (*currLevel).size(); i++)
		{
			if (N <= i) return (*currLevel)[i][N]>250 ? 250 : (*currLevel)[i][N];
			N -= i;
		}
		return -1;
	}

	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++)
		{
			scanf("%d %d %d", &B, &L, &N);
			level1.clear();
			level2.clear();
			level1.resize(402, vector<double>(402, 0));
			level2.resize(402, vector<double>(402, 0));
			fout << "Case #" << (time + 1) << ": " << setiosflags(ios::fixed) << setprecision(8)<< SingleProcess() << endl;
			std::cout << time << endl;
		}
		fclose(fp);
		fout.close();
	}
};

class CC
{
public:
	CC(){}
	vector<int> level1;
	vector<int> level2;
	vector<int> line;
	int N, K;
	int SingleProcess()
	{
		vector<int> *currLevel, *nextLevel;
		currLevel = &level1;
		nextLevel = &level2;
		currLevel->clear();
		nextLevel->clear();
		currLevel->resize(102, 0);
		nextLevel->resize(102, 0);
		line.push_back(0);//最后填一个永远不会被削掉的数字,方便处理越界
		for (int i = 0; i < N-2; i++)
		{
			if (line[i + 1] - line[i] == K&&line[i + 2] - line[i + 1] == K) (*currLevel)[i] = i + 3;
		}
		while (true)
		{
			int a, b, c;
			for (int i = 0; i < N-2; i++)
			{
				a = line[i];
				int t1, t2;

				t1 = i + 1;
				while (t1>0)
				{
					if (line[t1] - a == K)
					{
						t2 = t1 + 1;
						while (t2>0)
						{
							if (t2>0 && line[t2] - line[t1] == K)
							{
								(*nextLevel)[i] = max(currLevel->at(i), t2 + 1);
							}
							t2 = (*currLevel)[t2];
							if (t2 == 0) break;
						}
					}
					t1 = (*currLevel)[t1];
				}
			}
			
			bool findone = false;
			for (int i = 0; i < currLevel->size(); i++)
			{
				if (currLevel->at(i) != nextLevel->at(i))
				{
					(*nextLevel)[i] = max((*currLevel)[i], (*nextLevel)[i]);
					findone = true;
				}
			}
			if (!findone) break;
			swap(currLevel, nextLevel);
		}

		int ret = 0;
		for (int j = 0; j<N; )
		{
			if ((*currLevel)[j] == 0)
			{
				j++;
				ret++;
			}
			else
			{
				j = (*currLevel)[j];
			}
		}

		return 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++)
		{
			scanf("%d %d", &N,&K);
			line.resize(N, 0);
			for (int i = 0; i < line.size(); i++)
			{
				scanf("%d", &line[i]);
			}

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



class CD
{
public:
	CD(){}
	ll K, N;
	ll MAXK = 1e18;
	ll C[101][101];
	void initC()
	{
		for (int i = 0; i < 101; i++)
		{
			for (int j = 0; j < 101; j++)
			{
				if (i == 0) C[i][j] = 1;
				else if (i>j) C[i][j] = 0;
				else
				{
					C[i][j] = C[i][j - 1] + C[i - 1][j];
					if (C[i][j]>MAXK) C[i][j] = MAXK;
				}
			}
		}
	}

	string SingleProcess()
	{
		string ret = "";
		K--;
		if (C[N][N] <= K) return "Doesn't Exist!";
		int x, y;
		x = y = N;
		while (x > 0 || y >0)
		{
			if (x>0&&C[x - 1][y] > K)
			{
				x--;
				ret += "(";
			}
			else
			{
				if(x>0) K -= C[x - 1][y];
				y--;
				ret += ")";
			}
		}
		return ret;
	}

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

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





int main()
{
	CA p;
	//CB p;
	//CC p;
	//CD p;
	p.run();

	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值