【复习】noip2001

第七届(2001)分区联赛复赛试题

(提高组)

内存限制128MB,时限1

 

 

第一题:一元三次方程求解

(p1.pas p1.in p1.out)

问题描述

有形如:ax3+bx2+cx+d=0  这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)*f(x2)<0,则在(x1,x2)之间一定有一个根。

样例
输入:1   -5   -4   20
输出:-2.00   2.00   5.00

 

第二题:数的划分

(p2.pas/c/cpp p2.in p2.out)

问题描述

将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序)。例如:n=7,k=3,下面三种分法被认为是相同的。1,1,5; 1,5,1; 5,1,1;问有多少种不同的分法。
输入:n,k (6<n<=200,2<=k<=6)
输出:一个整数,即不同的分法。

样例
输入: 7 3
输出:4 {四种分法为:1,1,5;1,2,4;1,3,3;2,2,3;}

 

 


第三题:统计单词个数

(p3.pas/c/cpp  p3.in  p3.out)

问题描述

给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
输入格式:输入数据放在文本文件p3.in中,其格式如下:第一行为一个正整数(0<n<=5)表示有n组测试数据每组的第一行有二个正整数(p,k),p表示字串的行数;k表示分为k个部分。接下来的p行,每行均有20个字符。再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)接下来的s行,每行均有一个单词。
输出格式:结果输出至屏幕,每行一个整数,分别对应每组测试数据的相应结果。

样例
输入:
1
1 3
thisisabookyouareaoh
4
is
a
ok
sab
输出: //说明:(不必输出
)
7 // this/isabookyoua/reaoh

 


第四题:CAR的旅行路线

(p4.pas/c/cpp  p4.in  p4.out)

问题描述

又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。

x

y

那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。
任务:找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。
输入文件:输入文件名p4.in
输 出:p4.out(输出最小费用,小数点后保留1位。
)
输入格式:第一行为一个正整数n(0<=n<=10),表示有n组测试数据。每组的第一行有四个正整数s,t,A,B。S(0<S<=100)表示城市的个数,t表示飞机单位里程的价格,A,B分别为城市A,B的序号,(1<=A,B<=S)。接下来有S行,其中第I行均有7个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti,这当中的(xi1,yi1),(xi2,yi2),(xi3,yi3)分别是第I个城市中任意三个机场的坐标,T I为第I个城市高速铁路单位里程的价格。

输出格式:共有n行,每行一个数据对应测试数据。

样例
输入
1
3 10 1 3
1 1 1 3 3 1 30
2 5 7 4 5 2 1
8 6 8 8 11 6 3
输出:
47.5

 

 

这套题已经没有太大价值了,历史太久远。第一次测300分,因为第三题有点没有理解清楚题意。

1、2、4题没有太多讨论的价值,直接贴上代码。

另外4题,这种题还是有做的价值的,这种题是必过的,但是不一定正式考试能够足够冷静,这种题只要不慌乱,就能拿全!所以要训练自己的细致和严谨,因为正式考试不可能像平时这般轻松,平常需要更加地细心,正式考试才能不乱。

 

#include <cstdio>
double a,b,c,d;
double eps = 1e-11;

int main()
{
	freopen("p1.in","r",stdin);
	freopen("p1.out","w",stdout);
	scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
	//if (abs(-a*1000000+b*10000-c*100+d)<eps)
	//	printf("-100 ");
	for (double x=-100.000-0.001;x<=100.000-0.001;x+=0.001)
	{
		double xx = x*x;
		double xxx = xx*x;
		double x2 = x+0.001;
		double xx2 = x2*x2;
		double xxx2 = xx2*x2;
		double rs1 = (a*xxx+b*xx+c*x+d);
		double rs2 = (a*xxx2+b*xx2+c*x2+d);
		if (rs1<-eps&&rs2>eps || rs1>eps&&rs2<-eps)
			printf("%.2lf ",x+0.0005);
	}
	return 0;
}

#include <cstdio>
long n,k;
long ans = 0;

void dfs(long u,long last,long sum)
{
	if (u == k)
	{
		if (n-sum>=last)
			ans ++;
		return;
	}
	for (long i=last;i+sum<n+1;i++)
	{
		dfs(u+1,i,sum+i);
	}
}

int main()
{
	freopen("p2.in","r",stdin);
	freopen("p2.out","w",stdout);

	scanf("%ld%ld",&n,&k);
	dfs(1,1,0);
	printf("%ld",ans);
	return 0;
}


 

#include <cstdio>
#include <cmath>
#include <string>

double dist[510];
double len[510][510];
bool used[510];
long x[510];
long y[510];
long t[110];
long n;
long tf;
long A;
long B;
long cnt;

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp=getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){tmp=getchar();sgn=1;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

void dijkstra(long u)
{
	for (long i=0;i<n;i++)
	{
		dist[i] = len[u][i];
		used[i] = false;
	}
	dist[u] = 0;
	for (long l=1;l<n;l++)
	{
		double nearest=0x7f7f7f7f;
		long k = -1;
		for (long i=0;i<n;i++)
		{
			if (!used[i] && dist[i]<nearest)
			{
				nearest = dist[i];
				k = i;
			}
		}
		used[k] = true;
		for (long i=0;i<n;i++)
			if (!used[i] && dist[i]>dist[k]+len[k][i])
				dist[i] = dist[k] + len[k][i];
	}
}

int main()
{
	freopen("p4.in","r",stdin);
	freopen("p4.out","w",stdout);

	long T = getint();
	while (T --)
	{
		n = getint();
		tf = getint();
		A = getint();
		B = getint();
		cnt = -1;

		for (long i=0;i<n;i++)
		{
			long x1,x2,x3,x4,y1,y2,y3,y4;
			x1 = getint();y1 = getint();
			x2 = getint();y2 = getint();
			x3 = getint();y3 = getint();
			cnt++;x[cnt] = x1;y[cnt] = y1;
			cnt++;x[cnt] = x2;y[cnt] = y2;
			cnt++;x[cnt] = x3;y[cnt] = y3;

			x4 = x1+x2-x3;
			y4 = y1+y2-y3;
			if ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) != (x4-x3)*(x4-x3)+(y4-y3)*(y4-y3))
			{
				x4 = x2+x3-x1;
				y4 = y2+y3-y1;
				if ((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2) != (x4-x1)*(x4-x1)+(y4-y1)*(y4-y1))
				{
					x4 = x1+x3-x2;
					y4 = y1+y3-y2;
				}
			}
			cnt++;x[cnt] = x4;y[cnt] = y4;
			t[i] = getint();
		}
		n *= 4;
		for (long i=0;i<n;i++)
			for (long j=i+1;j<n;j++)
			{
				if (j/4 == i/4)
					len[i][j] = len[j][i] = sqrt(double((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])))*double(t[i/4]);
				else
					len[i][j] = len[j][i] = sqrt(double((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])))*double(tf);
			}

		double ans = 1e19;
		A--;B--;
		for (long i=A*4;i<A*4+4;i++)
		{
			dijkstra(i);
			for (long j=B*4;j<B*4+4;j++)
				if (dist[j] < ans)
					ans = dist[j];
		}
		printf("%.1lf\n",ans);
	}
	return 0;
}

 

第三题还是值得一提。

 

每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th


这句话需要理解清楚,我就是卡在了这句话上。它的意思是同一位置不能多次作为首字母。而并不是说两个相同首字母的单词不能重复使用。

这样的话,就很简单了,因为预处理区间内最多的单词数,是一个固定的值,而不存在找最优。我们只需要贪心,以每一个位置为起点,能找到任意一个匹配的单词,就把g[i][j]加一。

动规部分很简单,都能非常容易地想出来。f[i][k] = max(f[j][k-1]+g[j+1][i])

 

需要注意的是,动规的初值,绝对不能小窥,我再一次错在了这里,以后再也不错这里了!!

很简单,比如[1,3]这个区间没有匹配的单词,而[3,4]有一个匹配的单词,如果不初始化为负无穷,则f[4][2]会是2,这当然是错的!因为f[3][1]实际上是无效状态。

 

#include <cstdio>
#include <string>
#define max(a,b) ((a)>(b)?(a):(b))

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp=getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp=='-'){sgn=0;tmp=getchar();}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

char word[10][210];
char str[210];
long g[210][210];
long f[210][50];
long len;
long n;

void pre(long l,long r)
{
	for (long i=l;i<r+1;i++)
	{
		for (long j=1;j<n+1;j++)
		{
			if (i+word[j][0]-1<r+1)
			{
				bool ok = true;
				for (long x=1;x<word[j][0]+1;x++)
				{
					if (str[i+x-1]!=word[j][x])
					{
						ok = false;
						break;
					}
				}
				if (ok)
				{
					g[l][r] ++;
					break;
				}
			}
		}
	}

}

int main()
{
	freopen("p3.in","r",stdin);
	freopen("p3.out","w",stdout);
	long T = getint();
	while (T--)
	{
		memset(g,0,sizeof g);
		memset(f,0,sizeof f);
		long tmp = getint();
		long K = getint();
		len = tmp * 20;
		for (long i=0;i<tmp;i++)
			scanf("%s",str+i*20+1);
		n = getint();
		for (long i=1;i<n+1;i++)
		{
			word[i][0] = 0;
			scanf("%s",word[i]+1);
			while (word[i][++word[i][0]]);
			word[i][0] --;
		}

		for (long i=1;i<len+1;i++)
			for (long j=i;j<len+1;j++)
				pre(i,j);

		memset(f,0x80,sizeof f);
		
		for (long i=1;i<len+1;i++)
			f[i][1] = g[1][i];

		for (long i=1;i<len+1;i++)
		{
			for (long j=1;j<i;j++)
			{
				for (long k=2;k<K+1;k++)
				{
					f[i][k] = max(f[i][k],f[j][k-1]+g[j+1][i]);
				}
			}
		}

		printf("%ld\n",f[len][K]);
	}
	return 0;
}


 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值