直线与圆的位置关系

直线和圆

现在有一条直线和一个圆。请写一个程序判断它们的位置关系。其中0代表直线和圆相离,1代表两者相切,2代表两者相交。

给定直线上的两个点(不重合)的坐标x1,y1,x2,y2,另外给定圆心坐标xc,yc和圆的半径r。请返回判断的结果(0或1或2)。

测试样例:
-1,-1,1,1,0,0,2
返回:2
时间限制:
1秒
内存限制:
32768KB

AC代码:

class LineAndCircle {
public:

	double cmpzero(double x)
	{
		double eps = 1e-9;
		return fabs(x)<eps ? 0 : x;
	}
    //(x1,y1)和(x2,y2)是线段的两个点, (xc,yc)是圆心,r是半径
	int judgeStat(double x1, double y1, int x2, int y2, int xc, int yc, int r) {
		set<pair<double, double>> p;
		double MIN_VALUE = 1e-8;  //根据需要调整这个值
		double X0 = xc, Y0 = yc;
		double X1 = x1, Y1 = y1;
		double X2 = x2, Y2 = y2;
		double R = r;
		double DX = X2 - X1, DY = Y2 - Y1;
		double A = DX*DX + DY*DY;
		double B = 2 * DX*(X1 - X0) + 2 * DY*(Y1 - Y0);
		double C = (X1 - X0)*(X1 - X0) + (Y1 - Y0)*(Y1 - Y0) - R*R;
		double DELTA = B*B - 4 * A*C;
		int num = 0;
		if (cmpzero(DELTA)>= 0)
		{
			double T1 = (-B - sqrt(DELTA)) / (2 * A);
			double T2 = (-B + sqrt(DELTA)) / (2 * A);
			p.insert({ X1 + T1*DX, Y1 + T1*DY });
			p.insert({ X1 + T2*DX, Y1 + T2*DY });
		}
		return p.size();
	}
};

C++11新特性:智能指针与lambda表达式

1.智能指针

说到智能指针,我们不能不提到C++里面的动态内存管理。在C++里,我们通常使用new来动态分配内存,用delete来释放内存。这两个操作都需要我们自己写到合适的地方,但这样会存在一个问题:假如在new了之后在delete之前抛出异常,那么我们的代码很有可能就没有执行delete操作,从而导致new创建的内存一直无法释放。

那么怎么解决这个问题呢?

智能指针就是用来解决这个问题的,智能指针和常规的指针最重要的区别就是,它能够负责自动释放内存,其它方面和常规的指针一样。这么一来,就可以避免上面的问题了。

share_ptr是用来创建指针,结合以前的new用法:share_ptr<int> tmp=new int(10);

那么我们怎么知道share_ptr的对象是否还存在呢?我们通过weak_ptr,weak_ptr相当于一个工具,用来配合share_ptr使用,可以读取share_ptr的计数器值,当读取到的值为0时,share_ptr的对象也就不存在了。

 

2.lambda表达式

lambda表达式能够把一些函数直接写成表达式,无须函数名字,例如我们使用sort函数自定义比较时:

需要定义cmp函数,并调用cmp函数,但是假如使用lambda表达式,我们就无需要把比较的表达式封装成函数,如下:

sort(array.begin(),array.end(),[](const int&a,const int&b){return a>b;});

这样,我们就不需要因为自定义比较而特意去定义一个函数并给它起名字。

问题:求1到n这n个整数间的异或值,即 1 xor 2 xor 3 … xor n

我们记
QQ截图20151227163719
为a到b之间所有数的异或(包括a和b)。

那么我们先来考虑

QQ截图20151227163919,一共是2^k个数。这2^k个数中,二进制中最高位为1的是第k+1位,且所有2^k个数的最高位均为1。

 

我们考虑k>=1,则2^k为偶数,最高位异或后为0,把这个数的最高位去掉,并不会影响QQ截图20151227163919的值,所以公式1

所以:QQ截图20151227164135
QQ截图20151227164150

对于QQ截图20151227164214,设n的最高位1是在第k+1位(k>=2),

QQ截图20151227164249,对于2^k到n一共m=n+1-2^k个数,最高位共有m=n+1-2^k个1。
(1)当n为奇数时,m=n+1-2^k为偶数,根据公式1,可以进一步化为:QQ截图20151227164359 由于n-2^k和n都是奇数,递推上面的公式,可以得到QQ截图20151227164514

为什么会得到这个公式?QQ截图20151227164359相当于把n去掉其最高位,经过多轮递推后,n只剩下两个位,为什么剩下两个位?因为k>=2,所以剩下的两位无法再进行递推。又因为n为奇数,所以n不是1就是3,写成通项公式的话,就是QQ截图20151227164514

所以最终有:
QQ截图20151227164607

(2)当n为偶数时,m=n+1-2^k为奇数,则最高位共有奇数m=n+1-2^k个1,QQ截图20151227164650,最后和2^k相或,是因为最高位有奇数个1。

经过递推,我们可以知道,n二进制表示中,原来是1的位,依然是1,原来为0的位,依然为0,因为每次递推都会把当时最高位1保留下来,因为k>=2,实则相当于把n的前k-2为保留下来。

n的二进制表示为:QQ截图20151227164751n’记为:QQ截图20151227164822

,即把n的最后两位清零, 那么上述公式可以化为:

QQ截图20151227164840
即当n%4=0时,即n=n’,所以QQ截图20151227164906当n%4=2时,即n=n’+2,所以QQ截图20151227164940

综上所述:QQ截图20151227164958

 

 

#1043 : 完全背包

题目:
1.实则为一个完全背包问题。
2.使用动态规划求解:
dp[i][j]表示从前i个物品开始选择,重量不超过j时,背包的最大价值。
dp[n][m]为最终答案。
状态转移方程为:

//背包空余重量不足
if (weight[i]>j) dp[i + 1][j] = dp[i][j];
//动态规划,选和不选的情况
else
dp[i + 1][j] = max(dp[i][j], dp[i+1][j – weight[i]] + value[i]);

注意是dp[i+1][j – weight[i]]

3.写了两个版本,其中一个是没有优化的,一个是优化的版本。其中需要注意:
(1)优化版本只采用dp[j]
(2)因为dp[i + 1][j] = max(dp[i][j], dp[i+1][j – weight[i]] + value[i])需要使用到dp[i+1][j-weight[i]]的值,所以在遍历重量的时候需要从前面开始遍历:
for (int j = 0; j <= m; j++)
这是和01背包不同的地方!

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

且说之前的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

等等,这段故事为何似曾相识?这就要从平行宇宙理论说起了………总而言之,在另一个宇宙中,小Ho面临的问题发生了细微的变化!

小Ho现在手上有M张奖券,而奖品区有N种奖品,分别标号为1到N,其中第i种奖品需要need(i)张奖券进行兑换,并且可以兑换无数次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一: 切,不就是0~1变成了0~K么

提示二:强迫症患者总是会将状态转移方程优化一遍又一遍

提示三:同样不要忘了优化空间哦!

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的种数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一种奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。

样例输入
5 1000
144 990
487 436
210 673
567 58
1056 897
样例输出
5940

AC代码:

/*
题目:
1.实则为一个完全背包问题。
2.使用动态规划求解:
dp[i][j]表示从前i个物品开始选择,重量不超过j时,背包的最大价值。
dp[n][m]为最终答案。
状态转移方程为:

//背包空余重量不足
if (weight[i]>j) dp[i + 1][j] = dp[i][j];
//动态规划,选和不选的情况
else
dp[i + 1][j] = max(dp[i][j], dp[i+1][j - weight[i]] + value[i]);

注意是dp[i+1][j - weight[i]] 

3.写了两个版本,其中一个是没有优化的,一个是优化的版本。其中需要注意:
(1)优化版本只采用dp[j]
(2)因为dp[i + 1][j] = max(dp[i][j], dp[i+1][j - weight[i]] + value[i])需要使用到dp[i+1][j-weight[i]]的值,所以在遍历重量的时候需要从前面开始遍历:
for (int j = 0; j <= m; j++)
这是和01背包不同的地方!

*/
/*
*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;

/*
函数名  :main
函数功能:主函数
*/
int main(void)
{
	
	//int n, m;
	//cin >> n >> m;
	//vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
	//vector<int> value(n, 0);
	//vector<int> weight(n, 0);
	//for (int i = 0; i < n; i++)
	//{
	//	scanf("%d %d", &weight[i], &value[i]);
	//}

	//for (int i = 0; i < n; i++)
	//{
	//	for (int j = 0; j <= m; j++)
	//	{
	//		//背包空余重量不足
	//		if (weight[i]>j) dp[i + 1][j] = dp[i][j];
	//		//动态规划,选和不选的情况
	//		else
	//			dp[i + 1][j] = max(dp[i][j], dp[i+1][j - weight[i]] + value[i]);
	//	}
	//}

	//cout << dp[n][m] << endl;
	//

	//优化版本:
	int n, m;
	cin >> n >> m;
	vector<int> dp(m + 1, 0);
	vector<int> value(n, 0);
	vector<int> weight(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d %d", &weight[i], &value[i]);
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= m; j++)
		{//因为dp[j-weight[i]]是引用了前面的数组,所以需要从后面开始遍历
			//背包空余重量不足
			if (weight[i]>j) dp[j] = dp[j];
			//动态规划,选和不选的情况
			else
				dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
		}
	}

	cout << dp[m] << endl;


	return  0;
}

#1038 : 01背包

题目:
1.实则为一个01背包问题。
2.使用动态规划求解:
dp[i][j]表示从前i个物品开始选择,重量不超过j时,背包的最大价值。
dp[n][m]为最终答案。
状态转移方程为:

//背包空余重量不足
if (weight[i]>j) dp[i + 1][j] = dp[i][j];
//动态规划,选和不选的情况
else
dp[i + 1][j] = max(dp[i][j], dp[i][j – weight[i]] + value[i]);

3.写了两个版本,其中一个是没有优化的,一个是优化的版本。其中需要注意:
(1)优化版本只采用dp[j]
(2)因为dp[i + 1][j] = max(dp[i][j], dp[i][j – weight[i]] + value[i])需要使用到dp[i][j-weight[i]]的值,所以在遍历重量的时候需要从后面开始遍历:
for (int j = m; j >= 0; j–)

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一:合理抽象问题、定义状态是动态规划最关键的一步

提示二:说过了减少时间消耗,我们再来看看如何减少空间消耗

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的个数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一个奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。

样例输入
5 1000
144 990
487 436
210 673
567 58
1056 897
样例输出
2099

AC代码:

/*
题目:
1.实则为一个01背包问题。
2.使用动态规划求解:
dp[i][j]表示从前i个物品开始选择,重量不超过j时,背包的最大价值。
dp[n][m]为最终答案。
状态转移方程为:

//背包空余重量不足
if (weight[i]>j) dp[i + 1][j] = dp[i][j];
//动态规划,选和不选的情况
else
dp[i + 1][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

3.写了两个版本,其中一个是没有优化的,一个是优化的版本。其中需要注意:
(1)优化版本只采用dp[j]
(2)因为dp[i + 1][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i])需要使用到dp[i][j-weight[i]]的值,所以在遍历重量的时候需要从后面开始遍历:
for (int j = m; j >= 0; j--)

*/
/*
*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;

/*
函数名  :main
函数功能:主函数
*/
int main(void)
{
	/*
	int n, m;
	cin >> n >> m;
	vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
	vector<int> value(n, 0);
	vector<int> weight(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d %d", &weight[i], &value[i]);
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			//背包空余重量不足
			if (weight[i]>j) dp[i + 1][j] = dp[i][j];
			//动态规划,选和不选的情况
			else
				dp[i + 1][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);
		}
	}

	cout << dp[n][m] << endl;
	*/

	//优化版本:
	int n, m;
	cin >> n >> m;
	vector<int> dp(m + 1, 0);
	vector<int> value(n, 0);
	vector<int> weight(n, 0);
	for (int i = 0; i < n; i++)
	{
		scanf("%d %d", &weight[i], &value[i]);
	}

	for (int i = 0; i < n; i++)
	{
		for (int j = m; j >= 0; j--)
		{//因为dp[j-weight[i]]是引用了前面的数组,所以需要从后面开始遍历
			//背包空余重量不足
			if (weight[i]>j) dp[j] = dp[j];
			//动态规划,选和不选的情况
			else
				dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
		}
	}

	cout << dp[m] << endl;


	return  0;
}

#1107 : Shortest Proper Prefix

题目:
1.题目涉及到了一个proper prefix和shortest proper prefix。
2.proper prefix是指真前缀,即包含这个前缀的单词小于等于5个。
3.shortest proper prefix是指最短真前缀,是指除了它之外的前缀(可以理解为比它长的前缀)都不是真前缀。
所以我们要求出这样一个集合:
(1)集合中任意前缀对应的单词数量小于等于5;
(2)对于集合中任意前缀p,p的扩展前缀不属于该集合。

这是一道Trie的题目,需要建立Trie树。
我采用了map<char,Trie*> child的结构存储子节点。
在建立树的过程中,通过单词个数,最后进行深度搜索(或者广度搜索),找出<=5的节点的个数,需要注意的是,如果节点的count<=5,则不再遍历它的儿子节点,否则需要遍历它的儿子节点。

问题所在:
1.为了提高速度,我是用了char数组和scanf进行输入。
2.之前我分配的char数组大小为1000、10000、100000,均会出现Runtime Error(RE错误)
3.然后我把代码放到hiho第七十八周的挑战赛上,发现能够得分60,但是仍然RE错误,证明部分测试用例是正确的。
4.接着我把char数组改成string输入,再提交,发现得分能够到达70分,但是错误已经变成TLE,超时错误。
5.于是我开始测试是不是char数组大小不满足要求,把数组大小改为1000000,即100万的长度,终于AC了。

 

时间限制:10000ms
单点时限:1000ms
内存限制:512MB

描述

14214822852319.png

Query auto-completion(QAC) is widely used in many search applications. The basic idea is that when you type some string s in the search box several high-frequency queries which have s as a prefix are suggested. We say string s1 has string s2 as a prefix if and only if the first |s2| characters of s1 are the same as s2 where |s2| is the length of s2.

These days Little Hi has been working on a way to improve the QAC performance. He collected N high-frequency queries. We say a string s is a proper prefix if there are no more than 5 collected queries have s as a prefix. A string s is a shortest proper prefix if s is a proper prefix and all the prefixes of s(except for s itself) are not proper prefixes. Little Hi wants to know the number of shortest proper prefixes given N collected queries.

Hint: the 4 shortest proper prefixes for Sample Input are “ab”, “bb”, “bc” and “be”. Empty string “” is not counted as a proper prefix even if N <= 5.

输入

The first line contains N(N <= 10000), the number of collected queries.

The following N lines each contain a query.

Each query contains only lowercase letters ‘a’-‘z’.

The total length of all queries are no more than 2000000.

Input may contain identical queries. Count them separately when you calculate the number of queries that have some string as a prefix.

输出

Output the number of shortest proper prefixes.

样例输入
12
a
ab
abc
abcde
abcde
abcba
bcd
bcde
bcbbd
bcac
bee
bbb
样例输出
4

AC代码:

/*
题目:
1.题目涉及到了一个proper prefix和shortest proper prefix。
2.proper prefix是指真前缀,即包含这个前缀的单词小于等于5个。
3.shortest proper prefix是指最短真前缀,是指除了它之外的前缀(可以理解为比它长的前缀)都不是真前缀。
所以我们要求出这样一个集合:
(1)集合中任意前缀对应的单词数量小于等于5;
(2)对于集合中任意前缀p,p的扩展前缀不属于该集合。

这是一道Trie的题目,需要建立Trie树。
我采用了map<char,Trie*> child的结构存储子节点。
在建立树的过程中,通过单词个数,最后进行深度搜索(或者广度搜索),找出<=5的节点的个数,需要注意的是,如果节点的count<=5,则不再遍历它的儿子节点,否则需要遍历它的儿子节点。

问题所在:
1.为了提高速度,我是用了char数组和scanf进行输入。
2.之前我分配的char数组大小为1000、10000、100000,均会出现Runtime Error(RE错误)。
3.然后我把代码放到hiho第七十八周的挑战赛上,发现能够得分60,但是仍然RE错误,证明部分测试用例是正确的。
4.接着我把char数组改成string输入,再提交,发现得分能够到达70分,但是错误已经变成TLE,超时错误。
5.于是我开始测试是不是char数组大小不满足要求,把数组大小改为1000000,即100万的长度,终于AC了。

*/
/*
*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;

struct Trie{
	map<char, Trie*> child;
	int count;
	Trie() :count(0){};
	Trie(int x) :count(x){};
};

void InsertWord(char *a, int pos, Trie*p)
{
	if (a[pos] == 0) return;//已经遍历完毕
	else
	{
		if (p->child.find(a[pos]) != p->child.end())
		{//找到有这个字母
			p->child[a[pos]]->count++;
			InsertWord(a, pos + 1, p->child[a[pos]]);
		}
		else
		{//没找到,则新插入一个
			p->child[a[pos]] = new Trie(1);//默认count为1
			InsertWord(a, pos + 1, p->child[a[pos]]);
		}
	}
}
void dfs(int &ans, Trie* root)
{
	if (root->count <= 5)
		ans++;
	else if (root->child.size())
	{
		for (map<char, Trie*>::iterator ite = root->child.begin(); ite != root->child.end(); ite++)
		{
			dfs(ans, ite->second);
		}
	}
}
/*
函数名  :main
函数功能:主函数
*/
int main(void)
{
	int n;
	Trie *root = new Trie;
	root->count = INT_MAX;
	char *word = new char[1000000];
	memset(word, 0, 1000000);
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		memset(word, 0, 1000000);
		scanf("%s", word);
		InsertWord(word, 0, root);
	}
	int ans = 0;
	dfs(ans, root);

	cout << ans << endl;

	return  0;
}

#1223 : 不等式

题目:

1.刚开始看得时候没有什么思路,后来看了一下C的范围,发现可以遍历所有情况。

2.因为C的范围是0到1000,最多有50条等式,所以采用遍历每个数值,看其满足的等式条数,最终取最大值。

3.注意我们遍历的时候,不能直接遍历0,1,2…;因为出现等式X > 2和X < 3,X=2.5能够同时满足要求。

4.遍历的时候使用0.5的步进进行判断。

5.输入的时候,cin>>string>>string>>int即可。

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

给定n个关于X的不等式,问最多有多少个成立。

每个不等式为如下的形式之一:

X < C

X <= C

X = C

X > C

X >= C

输入

第一行一个整数n。

以下n行,每行一个不等式。

数据范围:

1<=N<=50,0<=C<=1000

输出

一行一个整数,表示最多可以同时成立的不等式个数。

样例输入
4
X = 1
X = 2
X = 3
X > 0
样例输出
2

AC代码:

/*
题目:
1.因为C的范围是0到1000,最多有50条等式,所以采用遍历每个数值,看其满足的等式条数,最终取最大值。
2.注意我们遍历的时候,不能直接遍历0,1,2,3,4,5;因为出现等式X > 2和X < 3,X=2.5能够同时满足要求。
3.遍历的时候使用0.5的步进进行判断。

*/
/*

测试用例:

2
X > 2
X < 3
正确答案:
2


6
X = 1
X = 2
X = 3
X > 0
X >= 0
X <= 0
正确答案:
3

*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;
bool cal(float&x, pair<string, int>&e)
{
	string op = e.first;
	int c = e.second;
	if (op == "<")
		return x < c;
	else if (op == "<=")
		return x <= c;
	else if (op == ">")
		return x > c;
	else if (op == ">=")
		return x >= c;
	else
		return x == c;
	
}
/*
函数名  :main
函数功能:主函数
*/
int main(void)
{

	int n;
	cin >> n;
	vector<pair<string, int>> equation(n);
	string x;
	for (int i = 0; i < n; i++)
	{
		cin >> x >> equation[i].first >> equation[i].second;
	}
	int answer = 0;
	//遍历0到1000
	for (float x = -0.5; x <= 1000.5; x+=0.5)
	{
		int tmp = 0;
		//遍历所有的等式,求出满足的条数
		for (int i = 0; i < n; i++)
		{
			tmp += cal(x, equation[i]);
		}
		answer = max(tmp, answer);
	}
	cout << answer << endl;
	return  0;
}

#1197 : Give My Text Back

题目:

1.主要涉及字符串处理,把一些凌乱的句子转换为正常的句子。

2.字母之间只能够是空格或者逗号+空格或者句号+空格隔开。

3.一行里面可能有多个句子,这些句子不用换行,但是需要用句号+空格隔开,并且第一个字母需要大写。

4.注意最后结尾只能是句号,如果还包含有空格,则会出现Presentation Error。

4.主要是上面的情况,下面是一个测试用例及其正确的答案,这个测试用例正确,就能AC。

/*

测试用例:
 my Name  is Little   Hi. ami           .i hate      hiho                     ,codr. EEENNN.
   His   name IS Little ho  ,  We are   friends.
 my Name  is Little   Hi.His   name IS Little ho  ,  We are   friends.
my Name  is Little   Hi. His   name IS Little ho  ,  We are   friends.
 His   name IS Little ho  ,We are   friends.   weoifj   ,jo.
Jo, f, j l, o,o, l.

正确答案:
My name is little hi. Ami. I hate hiho, codr. Eeennn.
His name is little ho, we are friends.
My name is little hi. His name is little ho, we are friends.
My name is little hi. His name is little ho, we are friends.
His name is little ho, we are friends. Weoifj, jo.
Jo, f, j l, o, o, l.


*/

 

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

To prepare for the English exam Little Ho collected many digital reading materials. Unfortunately the materials are messed up by a malware.

It is known that the original text contains only English letters (a-zA-Z), spaces, commas, periods and newlines, conforming to the following format:

1. Each sentence contains at least one word, begins with a letter and ends with a period.

2. In a sentence the only capitalized letter is the first letter.

3. In a sentence the words are separated by a single space or a comma and a space.

4. The sentences are separated by a single space or a single newline.

It is also known the malware changes the text in the following ways:

1. Changing the cases of letters.

2. Adding spaces between words and punctuations.

Given the messed text, can you help Little Ho restore the original text?

输入

A string containing no more than 8192 English letters (a-zA-Z), spaces, commas, periods and newlines which is the messed text.

输出

The original text.

样例输入
my Name  is Little   Hi.
His   name IS Little ho  ,  We are   friends.
样例输出
My name is little hi.
His name is little ho, we are friends.

 
AC代码:

/*
题目:
1.主要涉及字符串处理。
2.字母之间只能够是空格或者逗号+空格或者句号+空格隔开。
3.一行里面可能有多个句子,这些句子不用换行,但是需要用句号+空格隔开,并且第一个字母需要大写。

*/
/*

测试用例:
 my Name  is Little   Hi. ami           .i hate      hiho                     ,codr. EEENNN.
   His   name IS Little ho  ,  We are   friends.
 my Name  is Little   Hi.His   name IS Little ho  ,  We are   friends.
my Name  is Little   Hi. His   name IS Little ho  ,  We are   friends.
 His   name IS Little ho  ,We are   friends.   weoifj   ,jo.
Jo, f, j l, o,o, l.

正确答案:
My name is little hi. Ami. I hate hiho, codr. Eeennn.
His name is little ho, we are friends.
My name is little hi. His name is little ho, we are friends.
My name is little hi. His name is little ho, we are friends.
His name is little ho, we are friends. Weoifj, jo.
Jo, f, j l, o, o, l.


*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;
char lower(char&c)
{
	if (c <= 'Z'&&c >= 'A') return c - 'A' + 'a';
	else return c;
}

char upper(char&c)
{
	if (c <= 'z'&&c >= 'a') return c - 'a' + 'A';
	else return c;
}
/*
函数名  :main
函数功能:主函数
*/
int main(void)
{

	string str;
	while (getline(cin, str))
	{
		string newStr="";
		bool blank = false;
		bool comma = false;
		bool period = false;
		for (int i = 0; i < str.size(); i++)
		{
			//如果是句子的开头,且str[i]元素不为空
			if (newStr == ""&&str[i]!=' ')
			{
				newStr += upper(str[i]);
			}
			//如果不是句子的开头
			else if (newStr != "")
			{
				//如果是句号
				if (str[i] == '.')
				{//标记之前记录的是句号
					period = true;
					newStr += str[i];
				}
				else if (str[i] == ',')
				{
					comma = true;
					newStr += str[i];
				}
				//标记空白
				else if (str[i]==' ')
					blank = true;
				else
				{
					//如果之前是句号,则这个是新的句子,要加上空白,并且字母要大写
					if (period)
					{
						newStr += ' ';
						newStr += upper(str[i]);
						period = false;
						comma = false;
						blank = false;
					}
					//如果之前是逗号或者是空白,则要加上空白,字母要小写
					else if (comma || blank)
					{
						newStr += ' ';
						newStr += lower(str[i]);
						period = false;
						comma = false;
						blank = false;
					}
					//其他情况,即只是字母,全部小写
					else
						newStr += lower(str[i]);
				}

			}
		}
		cout << newStr << endl;
	}
	return  0;
}

#1037 : 数字三角形

1.题目求一三角形(树)中,从根到叶子节点总和的最大值。

2.如果进行深度搜索的话,时间复杂度会很大,所以采用动态规划。

3.动态规划状态转移方程为:

reward[i][j]=reward[i][j]+max(reward[i+1][j],reward[i+1][j+1])

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

问题描述

小Hi和小Ho在经历了螃蟹先生的任务之后被奖励了一次出国旅游的机会,于是他们来到了大洋彼岸的美国。美国人民的生活非常有意思,经常会有形形色色、奇奇怪怪的活动举办,这不,小Hi和小Ho刚刚下飞机,就赶上了当地的迷宫节活动。迷宫节里展览出来的迷宫都特别的有意思,但是小Ho却相中了一个其实并不怎么像迷宫的迷宫——因为这个迷宫的奖励非常丰富~

于是小Ho找到了小Hi,让小Hi帮助他获取尽可能多的奖品,小Hi把手一伸道:“迷宫的介绍拿来!”

小Ho选择的迷宫是一个被称为“数字三角形”的n(n不超过200)层迷宫,这个迷宫的第i层有i个房间,分别编号为1..i。除去最后一层的房间,每一个房间都会有一些通往下一层的房间的楼梯,用符号来表示的话,就是从第i层的编号为j的房间出发会有两条路,一条通向第i+1层的编号为j的房间,另一条会通向第i+1层的编号为j+1的房间,而最后一层的所有房间都只有一条离开迷宫的道路。这样的道路都是单向的,也就是说当沿着这些道路前往下一层的房间或者离开迷宫之后,小Ho没有办法再次回到这个房间。迷宫里同时只会有一个参与者,而在每个参与者进入这个迷宫的时候,每个房间里都会生成一定数量的奖券,这些奖券可以在通过迷宫之后兑换各种奖品。小Ho的起点在第1层的编号为1的房间,现在小Ho悄悄向其他参与者弄清楚了每个房间里的奖券数量,希望小Hi帮他计算出他最多能获得多少奖券。

提示一:盲目贪心不可取,搜索计算太耗时

提示二:记忆深搜逞神威,宽度优先解难题

提示三:总结归纳提公式,减少冗余是真理

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为一个正整数n,表示这个迷宫的层数。

接下来的n行描述这个迷宫中每个房间的奖券数,其中第i行的第j个数代表着迷宫第i层的编号为j的房间中的奖券数量。

测试数据保证,有100%的数据满足n不超过100

对于100%的数据,迷宫的层数n不超过100

对于100%的数据,每个房间中的奖券数不超过1000

对于50%的数据,迷宫的层数不超过15(小Ho表示2^15才3万多呢,也就是说……)

对于10%的数据,迷宫的层数不超过1(小Hi很好奇你的边界情况处理的如何?~)

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要多。

对于10%的数据,迷宫的构造满足:对于90%以上的结点,左边道路通向的房间中的奖券数比右边道路通向的房间中的奖券数要少。

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的最多奖券数。

样例输入
5
2
6 4
1 2 8
4 0 9 6
6 5 5 3 6
样例输出
28

AC代码:

/*
题目:

意思主要是从根到叶子节点,求出一个总和最大的路径的值。

主要使用动态规划,自底向上进行动态规划,每次挑选最大的值。
*/


#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;
/*
函数名  :main
函数功能:主函数
*/
int main(void)
{
	
	int n;
	scanf("%d", &n);
	int **reward = new int *[n];
	//输入数据
	for (int i = 0; i<n; i++)
	{
		reward[i] = new int[i + 1];
		for (int j = 0; j <= i; j++)
		{
			scanf("%d", &reward[i][j]);
		}
	}

	//自底向上,进行动态规划。
	for (int i = n - 2; i >= 0; i--)
	{
		for (int j = 0; j <= i; j++)
		{
			reward[i][j] = reward[i][j] + max(reward[i + 1][j], reward[i + 1][j + 1]);
		}
	}
	printf("%d\n", reward[0][0]);
	return  0;
}

#1143 : 骨牌覆盖问题·一

首先,这道题目是一道斐波那契数列的题目。
我们来分析一下,第三个图形是如何由前两个图形组成。

blog

 

 

扩展到第n个图形,我们有:

blog2

 

 

所以,f(n)=f(n-1)+f(n-2)

由于n可能会很大,所以我们需要一些计算的技巧。
斐波那契数列是可以由矩阵计算得到,如下:

[a,b]* [0,1] = [b,a+b]
[1,1]

令mat =
[0,1]
[1,1]

那么,理论上,我们乘以n个矩阵mat,就可以求得f(n),
但是n个矩阵相乘,时间复杂度为O(n),
这时候,我们采用快速幂运算来求解,可以把时间复杂度降为O(logn)。

其中,为了方便计算,编写了class matrix22,重载了乘法运算符。

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

骨牌,一种古老的玩具。今天我们要研究的是骨牌的覆盖问题:
我们有一个2xN的长条形棋盘,然后用1×2的骨牌去覆盖整个棋盘。对于这个棋盘,一共有多少种不同的覆盖方法呢?
举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式:

提示:骨牌覆盖

提示:如何快速计算结果

输入

第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000

输出

第1行:1个整数,表示覆盖方案数 MOD 19999997

样例输入
62247088
样例输出
17748018

AC代码:

/*
题目:
首先,这道题目是一道斐波那契数列的题目。
我们来分析一下,第三个图形是如何由前两个图形组成。
 ______           _______
|    | |   或    |  |____|
|____|_|         |__|____|

扩展到第n个图形,我们有:
 _____________           ______________
|           | |  或     |         |____|
|___________|_|         |_________|____|
所以,f(n)=f(n-1)+f(n-2)

由于n可能会很大,所以我们需要一些计算的技巧。
斐波那契数列是可以由矩阵计算得到,如下:

[a,b]* [0,1] = [b,a+b]
       [1,1]

令mat =[0,1]
       [1,1]

那么,理论上,我们乘以n个矩阵mat,就可以求得f(n),
但是n个矩阵相乘,时间复杂度为O(n),
这时候,我们采用快速幂运算来求解,可以把时间复杂度降为O(logn)。

*/

#include<string>
#include <iomanip>
#include<fstream>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
//#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
//#include<stack>
#include<vector>
#include <algorithm>
using namespace std;
#define MOD 19999997
class matrix22{
public:
	long long a1, a2;
	long long  b1, b2;
	matrix22() :a1(0), a2(1), b1(1), b2(1){};
	matrix22 operator*(const matrix22 tmp)
	{
		matrix22 mat;
		mat.a1 = (a1%MOD)*(tmp.a1%MOD) + (a2%MOD)*(tmp.b1%MOD);
		mat.a2 = (a1%MOD)*(tmp.a2%MOD) + (a2%MOD)*(tmp.b2%MOD);
		mat.b1 = (b1%MOD)*(tmp.a1%MOD) + (b2%MOD)*(tmp.b1%MOD);
		mat.b2 = (b1%MOD)*(tmp.a2%MOD) + (b2%MOD)*(tmp.b2%MOD);
		return mat;
	}
};
/*
函数名  :main
函数功能:主函数
*/
int main(void)
{
	int n;
	scanf("%d", &n);
	int dp1 = 1;
	int dp2 = 2;
	if (n <= 0) printf("0\n");
	else if (n == 1) printf("1\n");
	else if (n == 2) printf("2\n");
	else
	{
		n -= 3;
		matrix22 mat;
		matrix22 ans;
		while (n != 0)
		{
			//如果二进制该位为1,则ans*mat
			if (n & 1)
				ans = ans*mat;
			//mat每次与自身相乘,求得矩阵的1,2,4,8,16次方
			mat = mat*mat;
			n = (n >> 1);
		}
		//输出f(n)
		long long answer =( ans.a2 + 2 * ans.b2)%MOD;
		cout << answer << endl;

	}
	return  0;
}