2014年第七届 重庆 大学生程序设计大赛 【假】题解

没有测试数据,在网上搜到数据的就测了一下。但是。。应该,也许大概没错吧!


第一题:

真分数的个数,f[i] 表示[1,i]之间真分数的个数。  然后直接求出i的真分数个数,递推一下f[i] = f[i - 1] + g(i) 

时间复杂度O(n^2)


#include <iostream>
using namespace std;

inline int gcd(int a, int b)
{
	while (b != 0)
	{
		int tmp = b;
		b = a % b;	
		a = tmp;
	}
	return a;
}

int f[505];

int n;
int main()
{
	f[1] = f[0] = 0;
	for (int i = 2; i != 500 + 1; ++ i)
	{
		f[i] = f[i - 1] + 1;
		for (int j = 2; j != i; ++ j)
			if (gcd(i, j) == 1)	++f[i];
	}
	cin >> n;
	while (n -- )
	{
		int a, b;
		cin >> a>> b;	
		cout << f[b] - f[a - 1]<<endl;
	}
	reutrn 0;
}

第二题:

木棒三角形

看起来数据范围,强行O(n^3)穷举都能过?但是我还是O(n^2logn),穷举两层,然后用map判定所需要的第三条边是否存在。

但是n那么小,除非数据量巨大无比,应该没事吧~~~

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

bool f[105];
int a[105];
int n;
int main()
{
	while (scanf("%d", &n))
	{
		memset(f,false, sizeof(f));
		for (int i = 0;i != n; ++ i)
		{
			scanf("%d", a + i);
			f[a[i]] = true;
		}
		double ans = 0;
		if (n < 3)
		{
			printf("My God!\n");	
			continue;
		}
		for (int i = 0; i != n; ++ i)
			for (int j = 0; j != n; ++ j)//处理精度的瑕疵,可能有缺陷
			{
				if (i == j)	continue;
				double A = (double)a[i];
				double B = (double)a[j];
				double C = sqrt(A * A + B * B);
				int tmp = (int)C;
				if ((double)tmp != C)	continue;
				if (!f[tmp])	continue;
				if (tmp > a[i] && tmp > a[j])
				{
					double s = a[i] * a[j] / 2.0;
					ans = max(ans , s);
				}
			}
		if (ans == 0)	printf("MY God!\n");
		else printf("%lf\n", ans);
	}

}

第三题:

9个数字,直接暴力穷举所有删除情况,也就是最多2^9级别,才512。  

#include <iostream>
#include <cstdio>
using namespace std;


char c[15];
int n, ans, a, de;

void dfs(int p, int k, int tot, int JIE)
{
	if (p == -1)
	{
		if (k)	return;
		ans = max(ans, tot);
		return;
	}
	dfs(p - 1, k, tot + (c[p] - '0') * JIE, JIE * 10);
	dfs(p - 1, k - 1, tot, JIE);
}


int main()
{
	scanf("%d", &n);
	while (n -- )
	{
		ans = 0;
		scanf("%s %d", &c, &de);
		dfs(8, de, 0, 1);
		printf("%d\n", ans);
	}
	return 0;
}

第四题:

赤裸裸的高精度乘法,这没啥好说的(PS:没贴模板,发现我的程序好丑)

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

struct bigint
{
	int w;
	vector<int>a;
	bigint(string t)
	{

		w = t.size();
		for (int i = t.size() -1; i != 0 -1; -- i)
		a.push_back(t[i] - '0');
	}
	bigint(int n)
	{
		w = n;
		for (int i = 0; i != n; ++ i)	a.push_back(0);
	}
	void p()
	{
		for (int i = w - 1; i != 0 - 1; -- i)	cout<<a[i];
		cout<<endl;
	}
};

char c[500];

bigint operator * (bigint A, bigint B)
{
	bool flag = false;
	bigint C(A.w + B.w - 1);
	for (int i = 0; i != A.w; ++ i)
		for (int j = 0; j != B.w; ++ j)
		{
			C.a[i + j] += A.a[i] * B.a[j];
			int tmp = C.a[i + j] / 10;
			if (!tmp)	continue;
			if (i + j == C.w - 1 && !flag)	
			{
				flag = true;
				++ C.w;
				C.a.push_back(0);
			}
			C.a[i + j] %= 10;
			C.a[i + j + 1] += tmp;	
		}
	C.p();
	return C;
}

int main()
{
	int nn;
	scanf("%d\n", &nn);
	while (nn--)
	{
		gets(c);
		bigint A(c);
		gets(c);
		bigint B(c);
		(A * B);
	}
	return 0;
}

第五题:

经典动态规划数塔,f[i][j] = f[i-1][j -1] + f[i-1][j] 其中考虑一下边界(f[1][j])情况即可

#include <iostream>
#include <cstdio>
using namespace std;

int a[120][120];
int main()
{
	int t, n;
	scanf("%d", &t);
	while (t -- )
	{
		int ans = 0;
		scanf("%d", &n);
		for (int i = 0; i != n; ++i)
			for (int j = 0; j != i + 1; ++ j )	scanf("%d", &a[i][j]);
		for (int i = 1; i != n; ++ i)
		{
			a[i][0] += a[i - 1][0];
			for (int j = 1; j != i + 1; ++ j)	a[i][j] += max(a[i - 1][j], a[i - 1][j - 1]);
		}

		for (int i = 0; i !=n ; ++ i)	ans = max(ans, a[n - 1][i]);
		printf("%d\n", ans);
	}

}

第六题:

字符串判断存在性问题

这真是奇葩题,要考这个一般是考字母树之类的东西吧,但是这读入量,一次才1000. 直接省事用map来判断了...

#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
using namespace std;
char ch[1000 + 10];

map<string, int>t;
map<string, int>::iterator  k;
int main()
{
	while (1)
	{
		t.clear();
		gets(ch);
		if (ch[0] == '#')	break;
		string tmp = "";
		for (int i = 0; i != strlen(ch); ++ i )	
		{
			if (ch[i]==' ')
			{
				if (t.find(tmp) == t.end())	t.insert(pair<string, int>(tmp, 1));
				tmp = "";
				continue;
			}
			tmp += ch[i];
		}
		if (t.find(tmp) == t.end())	t.insert(pair<string, int>(tmp, 1));
		printf("%d\n", t.size());
	}
	return 0;
}

第七题:

模拟啊,按照规则模拟一下。 就是题目最后那一行字说明,最后不要输出多余回车。 这个小心一下,不然会WA

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

int n;
int a[25][2];
int main()
{
	scanf("%d", &n);
	while (1)	
	{
		for (int j = 0; j != 2; ++ j)	
			for (int i = 0; i != n; ++ i)	scanf("%d",&a[i][j]);	
		int A(0), B(0);
		for (int i = 0; i != n; ++ i)
		{
#define x a[i][0]
#define y a[i][1]
		//	int *x = &a[i][0], *y = &a[i][1];
			if (x == y)	continue;
			if (abs(x - y) == 1)
			{
				if (x == 1 && y == 2)	{	A += 6;	continue;	}
				if (x == 2 && y == 1)	{	B += 6;	continue;	}
				if (x < y)	A += x + y;
				else B += x + y;
				continue;
			}	
			if (x > y)	A += x;
			else B += y;
		}
		printf("A has %d points. B has %d points.\n", A, B);
		scanf("%d", &n);
		if (n)	printf("\n");
		else break;
	}
	return 0;
}

第八题:

终于有算法题了。。但是也太模板了。

凸包+求凸包面积的题。  数据量非常小,没啥复杂的地方,直接模板贴上过关

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;

const int max_n = 10000 + 10;
int n, top;
struct point
{
	double x, y;	
	point(double a, double b):x(a), y(b){}
	point():x(0),y(0){}
}pt[max_n], stack[max_n], t0;

double cross(point T, point A, point B)
{
	return (A.x - T.x)*(B.y - T.y) - (B.x - T.x)*(A.y - T.y);
}

double dis(point A, point B)
{
	return pow(A.x - B.x, 2) + pow(A.y - B.y, 2);
}


void findpoint()
{
	int num = 0;
	t0 = pt[0];
	for (int i = 1; i != n; ++ i)
		if (pt[i].x < t0.x || pt[i].x == t0.x && pt[i].y < t0.y)	t0 = pt[num = i];
	swap(pt[0], pt[num]);	
}

bool cmp(point A, point B) //显然希望 排序结果是, A 逆时针 到B
{
	double tmp = cross(t0, A, B);
	if (tmp > 0)	return true; 
	if (tmp < 0)	return false; 
	return dis(t0, A) > dis(t0, B);//相同的话,让距离远的在前面 ?  不同的人的程序好像这里都有区别?我感觉好像不影响什么
}


void graham()
{
	pt[n] = pt[0] ;
	stack[0] = pt[0];
	stack[1] = pt[1];
	stack[2] = pt[2];
	top = 2;
	for (int i = 3; i != n + 1;  ++ i)
	{
		while (top && cross(stack[top - 1], stack[top], pt[i]) <= 0)	-- top;
		stack[++top] = pt[i];
	}
}

int main()
{
	scanf("%d", &n);
	for (int i = 0; i != n; ++ i)	scanf("%lf%lf", &pt[i].x, &pt[i].y);
	findpoint();
	sort(pt + 1, pt + n, cmp);
	graham();
	int ans = 0;
	for (int i = 1; i != top; ++ i)
		ans += cross(t0 , stack[i - 1], stack[i]);
	cout<<ans/100<<endl;
	return 0;
}



总结:

没NOIP初中组难- -  陈题+ 水题 + 模板题

带了好的模板, 直接掉凸包和高精度。 剩下的题一点思维量都没有。  希望明年我参赛,能在2小时内ALL KILL

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值