冲刺noip2018 day1

版权声明:八月炊火的博客如需转载请注明出处 https://blog.csdn.net/qq_34990731/article/details/82970143

今天的题目挺水的,先上题目:
T1:
题目描述:
圆国是一个国家,它包含几个圆形地区。有些地区可能位于内其他地区,但其边界不相交或触摸。 Qatam是圆国的乡村居民。当他在两个地点之间旅行,他总是试图跨越过尽可能少的边界地区,因为跨越地区边界通常是费力的任务。
输入输出格式:
输入格式:
第一行,包含一个整数Num,表示测试数据的个数。(1<=Num<=10) 每组测试数据,第一行一个整数N,表示共有N个地区。1<=N<=50. 接下来三行,每行N个整数,前两行分别表示每个地区的x坐标和y坐标[-1000,1000],第三行表示该地区圆的半径r[1,1000]。 最后4个整数,分别表示Qatam的起点和目标点x1,y1,x2,y2[-1000,1000]。
输出格式:
共Num行,最少穿过的边界数目。
输入输出样例:
输入样例1:
5
1
0
0
2
-5 1 5 1
3
0 -6 6
0 1 2
2 2 2
-5 1 5 1
7
1 -3 2 5 -4 12 12
1 -1 2 5 5 1 1
8 1 2 1 1 1 2
-5 1 12 1
8
-3 2 2 0 -4 12 12 12
-1 2 3 1 5 1 1 1
1 3 1 7 1 1 2 3
2 3 13 2
12
-107 -38 140 148 -198 172 -179 148 176 153 -56 -187
175 -115 23 -2 -49 -151 -52 42 0 68 109 -174
135 42 70 39 89 39 43 150 10 120 16 8
102 16 19 -108
输出样例1:
0
2
3
5
3

T2:
题目描述:
任何一个整数N都能表示成另外两个整数a和b的平方差吗?如果能,那么这个数N就叫做Couple number。你的工作就是判断一个数N是不是Couple number。
输入输出格式:
输入格式:
仅一行,两个长整型范围内的整数n1和n2,之间用1个空格隔开。
输出格式:
输出在n1到n2范围内有多少个Couple number。 注意:包括n1和n2两个数,且n1<n2,n2 - n1 <= 10 000 000。
输入输出样例:
输入样例1:
1 10
输出样例1:
7

T3:
题目描述:
N位大牛排成一队,大牛的实力被编号为1~N(每位牛的实力两两不同),本来应该从1排到N,但他们排队常常出现混乱。有人认为是某些牛过于谦让,然而TH不是这么认为。 TH经过仔细推敲,做出如下定义: 一个队列的混乱程度正是逆序对数!序列(1, 4, 3, 2)的混乱程度为3,因为它含有三对逆序对(4, 3), (4, 2), (3, 2)。 一号牛每天都会在他的手册上写上两个新的数N、C,而他当天的计算机密码这是N位大牛排成混乱程度为C的队列的不同排列方式总数mod 1 000 000 007!
输入输出格式:
输入格式:
仅含一行两个数,N和C (1 ≤ N ≤ 1000, 0 ≤ C ≤ 10000).
输出格式:
一号牛当天的密码。
输入输出样例
输入样例1:
10 1
输出样例1:
9
输入样例2:
4 3
输出样例2:
6
输入样例3:
9 13
输出样例3:
17957

T4:
题目描述:
在2240年,一场巨大的战争在地球联合力量(EAF)与火星联盟(MF)之间展开。至今,双方势均力敌。因最近的一次经济危机,资源紧缺,EAF将被MF勒要更多领土。为此,EAF决定采取战争以来最重要的行动:发动对分散在MF上各处的基地进行同时攻击。EAF的力量大都是mechs——大型两足跛行车,有飞行功能。 典型的MF基地概况如下:构成基地的房屋地跨一到两块领土。每块领土被保护塔产生的穿不透的能量层所笼罩,以免于外来袭击。这些保护塔围绕在领土周围起保护作用。 每座保护塔通过建造在地面上的水道与至少一座塔相联系。当那些相联系的塔围成一圈,它们产生能量层。否则能量层消失。 MF知道如果能量层消失,基地将很容易被EAF的力量侵占,因此,被水道相连的两座塔保护水道免受军事袭击。每座塔有防御功能,能拆卸指定数量的mechs,每个水道在坍塌之前能解决特定数量敌方mechs的袭击。这个数量由水道连接的两塔能拆卸的总数量决定。两座塔不能被一个以上的水道相连。
在这里插入图片描述
但是,袭击塔一边的水道不减少塔在另一边能拆卸的mechs的数量。因为这次行动是突袭,所有的对水道的袭击都必须同时,所有水道同时坍塌瓦解。
在这里插入图片描述
所有能量层必须废除才算毁灭了一个MF基地。破坏所有水道能达此目的,但也将需要很多mechs 牺牲。EAF只有很少的力量花费了,必须最有效率地部署mechs。 你被赋予这任务,写程序:使EAF胜利。给定一幅保护塔的曲线图,决定哪些水道要被破坏,来使所有能量层消失,要求战斗中牺牲最少的mechs。
输入输出格式:
输入格式:
第一行为一个整数m,2 < m <= 100,代表塔的数量。 以下2m行,对于每个塔都有两行输入: 一行包含三个正整数i(0 <= i <= m-1),ui(1 <= ui <= 50),ci(1 <= ci <= m-1):每个塔的身份标识、可以摧毁的mechs的数量和与它相连的河道的数量。两个整数间用一个空格隔开。 一行包含ci个不同的正整数,代表和塔i连接的塔。一个塔不能连接到它自己,两个整数间用一个空格隔开。 该防御体系至少能够生成一个能量层。 不一定所有的塔连通。
输出格式:
一行一个整数,代表EAF摧毁所有能量层所需要消耗的最少数量的mechs。
输入输出样例:
输入样例1:
3
0 1 2
1 2
1 2 2
0 2
2 3 2
0 1
输出样例1:
3

题解:
T1:
知识点: 感觉这一题没有什么知识点,完全就是签到题(如果有dalao看出欢迎留言)。
讲解: 这一题一开始看没什么思路,多算了几个样例后发现我们只要统计一下起点和终点两个点上有多少圆覆盖就好了(注意如果起点和终点都在同一个圆里的话,那么这个圆不算),最后加起来就是答案了。
上代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int x[100],y[100],r[100];
bool check(int a,int b,int c,int x1,int y1)//计算(x1,y2)是否在以(a,b)为圆心半径为c的圆中 
{
	double num=(double)sqrt((a-x1)*(a-x1)+(b-y1)*(b-y1));
	if(num<=c)
		return true;
	else return false;
}
int main()
{
	int T;
	scanf("%d",&T);//多组测试数据 
	while(T--)
	{
		int n,x1,y1,x2,y2,much1=0,much2=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d",&x[i]);
		for(int i=1;i<=n;i++)
			scanf("%d",&y[i]);
		for(int i=1;i<=n;i++)
			scanf("%d",&r[i]);
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		for(int i=1;i<=n;i++)//每个圆都找一下 
		{
			if(check(x[i],y[i],r[i],x1,y1) && !check(x[i],y[i],r[i],x2,y2))//起点在一个圆中但终点不在 
				much1++;
			if(check(x[i],y[i],r[i],x2,y2) && !check(x[i],y[i],r[i],x1,y1))//终点在一个圆中但起点不在 
				much2++;
		}
		printf("%d\n",much1+much2);//输出一下答案 
	}
	return 0;
}

T2:
知识点: 数论
讲解: 这一题虽然是数论,可是我觉得是比较简单的数论了(如果这句话不小心伤害到了你,博主道歉,博主不是故意的),我们根据公式a^2 - b^2=(a+b)*(a-b),可以知道我们只要判断一个数可不可以分解成(a+b) * (a-b)的形式,我们继续观察,可以发现a+b和a-b一定同是奇数或同是偶数,而且如果是偶数的话一定是4的倍数,为什么?(下面的奇数偶数都是正的)如果同是奇数的话因为奇数有个1所以所有奇数都是,可同是偶数的话,偶数最小是2,那么(a+b) * (a-b)最小也只能是4,而且一定是4的倍数。知道了这个规律我们就不难写出AC的代码了。
上代码:

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
	long long l,r,ans=0;
	scanf("%lld %lld",&l,&r);//读入数据 
	for(long long i=l;i<=r;i++)//循环判断 
	{
		if(i%2!=0)//是奇数的情况 
			ans++;
		if(i%4==0)//是4的倍数的情况 
			ans++;
	}
	printf("%lld",ans);//输出答案 
	return 0;
}

T3:
知识点: 肯定得是DP啊。
讲解: 如果要计算方案数的话我们一定要知道有几头牛和出现几个逆序对,所以我们定义状态dp[i][j]表示总共i头牛,出现j个逆序对。然后我们可以知道如果要在i-1中多加一头牛的话,如果这头牛加在1号前面会有i-1个逆序对,然后往后以此类推,知道排在最后就没有逆序对产生所以我们可以写出状态转移方程:dp[i][j]=dp[i-1][j-i+1……j]的和,可是如果这样转移的话我们肯定会TLE,所以我们考虑改进一下状态转移方程,我们可以写成:dp[i][j]=dp[i][j-1]+dp[i-1][j]-dp[i-1][j-i],为什么可以这么写?对比上面的方程我们可以看出dp[i][j]和dp[i][j-1]唯一的差别就是dp[i][j]多了一个dp[i-1][j]而dp[i][j-1]则多了一个dp[i-1][j-i],那么我们把它们相差的处理一下就好了。
上代码:

#include<iostream>
#include<cstdio>
using namespace std;
long long dp[1010][10010],mod=1000000007;//注意要mod 
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=0;i<=n;i++)//处理一下边界 
		dp[i][0]=1;
	for(int i=1;i<=n;i++)//循环dp计算 
		for(int j=1;j<=m;j++)
			dp[i][j]=((dp[i][j-1]+dp[i-1][j])%mod-dp[i-1][max(j-i,-1)]+mod)%mod;//max(j-1,-1)的原因是防止数组越界,如果是j-i<0的话这个值一定是0,所以我们可以用-1代替 
	printf("%lld",dp[n][m]);//输出答案 
	return 0;
}

T4:
知识点: 图论:最大生成树
讲解:
这一题我觉得应该是这四题最难的了,首先经过分析我们知道我们要求的就是在一个有环的图中求删除边使他不成环,这个代价则是边权,边权则是链接的两个城市的需要mechs的数量,要使代价最小。一开始是想dfs的,dfs出所有环,并且找出环中的最小权边,发现写不了,于是我放弃了,然后动手算一下,发现删除后的图一定是一颗树,那么转化一下我们只要使删除后的树总权值最大不就好了,所以我们直接生成一个最大生成树,然后用总权值减去最大生成树就好了。
上代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct cheng
{
	int t,v;//t表示要多少mechs,v表示有多少防御塔与它相连 
}s[200];//存防御塔的信息 
struct Edge
{
	int x,y,u;//x和y表示这一条边所连的两个防御塔,u表示权值 
}a[20100];//存每一条边的信息 
int b[200][200],size=0,ans=0,f[200],n,vist[200][200];
bool cmp(const Edge x,const Edge y)//根据贪心我们采用权值从大到小排序 
{
	return x.u>y.u;
}
int getfather(int x)//并查集 
{
	if(f[x]==x)
		return x;
	f[x]=getfather(f[x]);
	return f[x];
}
void kruskal()
{
	int f1,f2,k=0;
	for(int i=0;i<n;i++)//初始化并查集 
		f[i]=i;
	for(int i=1;i<=size;i++)//按从大到小的顺序加边 
	{
		f1=getfather(a[i].x);//判断两个点是否存在环 
		f2=getfather(a[i].y);
		if(f1!=f2)//没有环的话就可以加 
		{
			f[f1]=f2;//合并一下并查集 
			ans+=a[i].u;//统计最大生成树的权值 
			k++;
			if(k==n-1)//如果已经生成够了则退出 
				break;
		}
	}
}
int main()
{
	int much=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)//读入数据 
	{
		int x;
		scanf("%d",&x);
		scanf("%d %d",&s[x].t,&s[x].v);
		for(int j=1;j<=s[x].v;j++)
			scanf("%d",&b[x][j]);
	}
	for(int i=0;i<n;i++)//我们处理处每一条边的信息 
	{
		for(int j=1;j<=s[i].v;j++)
		{
			if(vist[i][b[i][j]]==1)//为了避免重复边 
				continue;
			size++;
			a[size].x=i;
			a[size].y=b[i][j];
			a[size].u=s[i].t+s[b[i][j]].t;//处理信息 
			much+=a[size].u;//计算总权值 
			vist[i][b[i][j]]=1;//用来记录这条边是否处理过了 
			vist[b[i][j]][i]=1;
		}
	}
	sort(a+1,a+1+size,cmp);//排序一下 
	kruskal();//生成最大生成树 
	ans=much-ans;//相减一下 
	printf("%d",ans);//输出答案 
	return 0;
}

马上就要noip了,不知道考的怎么样。

猜你喜欢

转载自blog.csdn.net/qq_34990731/article/details/82970143