NOIP2012普及组复赛 解题分析

1.质因数分解

算法分析

n n n是两个不同的质数的乘积,如果求出较小的那个,也就求出较大的那个了。较小的那个小于根号 n n n。枚举法。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long 
using namespace std;
int isprime(int n)
{
	int i = 2, t = sqrt(n);
	while (i <= t && n % i != 0) ++i;
	if (i > t) return 1; else return 0;
}
int main()
{
	int n; 
	scanf("%d", &n);
	int t = sqrt(n);
	int i = 2;
	while (i <= t)
	{
		if (n % i == 0 && isprime(i)) break;
		++i;
	}
	printf("%d\n", n / i);
	return 0;
}

2.寻宝

算法分析

这道模拟题,在当年应该算是个大模拟了。按照题意模拟即可。需要注意的是,在每层找第 x x x个有楼梯的房间的时候,需要快速计算。假设这一层共有 t t t个带楼梯的房间,则 x % t x \% t x%t的意思就是走完若干轮之后,还需要在找几个带楼梯的房间。每次找的最大次数小于 m m m。整体时间复杂度 O ( n m ) O(nm) O(nm)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
struct node
{
	int id,  x;
};
node a[10010][110];
int main()  
{ 
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 0; j < m; ++j)
			scanf("%d%d", &a[i][j].id, &a[i][j].x);
	}
	int d;
	scanf("%d", &d);
	long long sum = 0;	
	for (int i = 1; i <= n; ++i)
	{		
		sum += a[i][d].x % 20123;
		int s = 0; // 该层有楼梯的所有房间总数 
		for (int j = 0; j < m; ++j)
			if (a[i][j].id == 1) ++s;
		int x = a[i][d].x % s + s;  // x不会等于0了,每次找最多多找一圈  
		// 从d号房间走x个有楼梯的房间即可 
		int t = 0;  // 计数  
		while (1)
		{
			if (a[i][d].id == 1) ++t;
			if (t == x) break;
		//	if (x == 0 && t == s) break;  // 
			++d;
		//	d %= m;
			if (d == m) d = 0;
		}		
	}
	printf("%lld\n", sum % 20123);
	return 0;
}

3.摆花

算法分析

题意可描述为: n n n种花,每种花不超过 a i a_i ai盆,需要选择 m m m盆摆放,问摆放方案数。同种花是一样的,摆放的时候按顺序摆放。

多重背包方案数问题。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int P = 1e6 + 7;
int n, m, a[110],f[110][110];
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	
	f[0][0] = 1;
	for (int i = 1; i <= n; ++i)
		for (int j = 0; j <= m; ++j)
			for (int k = 0; k <= a[i] && k <= j; ++k)
				f[i][j] = (f[i][j] + f[i-1][j - k]) % P;
		
	printf("%d\n", f[n][m]);
	return 0;
} 

4.文化之旅

算法分析

n < = 100 n <= 100 n<=100,各类最短路算法都能过。需要注意一些细节。

1.从起点到终点的路径上,不能出现相同的文化。可以记录前驱数组,到终点的时候,把路径还原检查就可以了。貌似不加这点,数据也都能过。

2.相同文化的点不能访问,和起点文化相同的点不能访问。

3.有重边。用二维数组存边权的时候,要取最小值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
int n, k, m, s, t;
int w[110][110], gx[110][110], c[110], dis[110], pre[110];
queue<int> q;
int vis[110], sv[110];
void chk(int u)
{
	if (pre[u]) chk(pre[u]);
	++sv[c[u]];
}
void spfa()
{
	memset(dis, 0x3f, sizeof(dis));
	dis[s] = 0;
	pre[s] = 0;
	vis[s] = 1;
	q.push(s);
	while (q.size())
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		for (int v = 1; v <= n; ++v)
			if (w[u][v] != 0x3f3f3f3f && c[v] != c[u] && c[v] != c[s] && (!gx[c[v]][c[u]]))
			{
				if (dis[v] > dis[u] + w[u][v])
				{
					if (v != t) 
					{
						dis[v] = dis[u] + w[u][v];
						pre[v] = u;
						if (!vis[v])
						{
							q.push(v); vis[v] = 1;
						}
					}
					else
					{
						pre[v] = u;
						memset(sv, 0, sizeof(sv));
						chk(t);
						int sok = 0;
						for (int i = 1; i <= k; ++i)
							if (sv[i] > 1)
							{
								sok = 1; break;
							}

						if (!sok) // 检查是否有一样的文化 
						{
							dis[v] = dis[u] + w[u][v];
							if (!vis[v])
							{
								q.push(v); vis[v] = 1;
							}
						}							 
					} 					
				}
			}
	}
}
int main()
{
	scanf("%d%d%d%d%d", &n, &k, &m, &s, &t);
	for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
	for (int i = 1; i <= k; ++i)
		for (int j = 1; j <= k; ++j)			
			{
				scanf("%d", &gx[i][j]);
			}
	//
	int u, v, d;
	memset(w, 0x3f, sizeof(w));
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d%d", &u, &v, &d);
		w[u][v] = min(w[u][v], d);
		w[v][u] = min(w[v][u], d);
	}
	// 
	spfa();
	//
	if (dis[t] != 0x3f3f3f3f) printf("%d\n", dis[t]);
	else printf("-1\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值