20200201B组考试总结

T1(数列)

题目描述
把一个正整数分成一列连续的正整数之和。这个数列必须包含至少两个正整数。你需要求出这个数列的最小长度。如果这个数列不存在则输出-1。
输入
每行包含一个正整数n。
每个文件包含多行,读入直到文件结束。
输出
对于每个n,输出一行,为这个数列的最小长度。
样例输入
9
2
样例输出
2
-1
数据范围
对于所有数据,n≤263
思路
这题我们发现,数据十分的大,可以找找规律。

  1. 奇数直接输出2,奇数+偶数
  2. 如果是2的次方,输出-1

那么还剩下不是2的次方的偶数。这一部分,我们选择暴力
我们暴力枚举答案,O(1)时间计算出等差序列的首项和末项,在求出等差序列总和,判断是否与N相等,若相等,输出;不相等,继续枚举

#include<cstdio>
#define rg register
using namespace std;
long long n,st,en,er[65];
bool bj;
long long sigma(long long x,long long y)
{
	if ((x+y)%2==0) return (x+y)/2*(y-x+1);
	else return (y-x+1)/2*(x+y);
}
int main()
{
	er[0]=1;
	for (rg int i=1;i<=63;i++)
		er[i]=er[i-1]<<1;
	while (scanf("%lld",&n)==true)
	{
		bj=false;
		if (n&1) printf("2\n");
		else
		{
			for (rg int i=0;i<=63;i++)
			{
				if (er[i]>=n)
				{
					if (er[i]==n) bj=true;
					break;	
				} 
			}
			if (bj) printf("-1\n");
			else
			{
				for (rg int i=3;;i++)
				{
					if (i&1) 
					{
						st=n/i-(i>>1);
						en=n/i+(i>>1);
						if (sigma(st,en)==n) 
						{
							printf("%d\n",i);
							break;
						}
					}
					else
					{
						st=n/i-(i>>1)+1;
						en=n/i+(i>>1);
						if (sigma(st,en)==n)
						{
							printf("%d\n",i);
							break;
						}
					}
				}
			}
		}
	}
	return 0;
}

T2(树)

题目描述
在这个问题中,给定一个值S和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和达到S。路径中节点的深度必须是升序的。假设节点1是根节点,根的深度是0,它的儿子节点的深度为1。路径不必一定从根节点开始。
输入
第一行是两个整数N和S,其中N是树的节点数。
第二行是N个正整数,第i个整数表示节点i的正整数。
接下来的N-1行每行是2个整数x和y,表示y是x的儿子。
输出
输出路径节点总和为S的路径数量。
样例输入
3 3
1 2 3
1 2
1 3
样例输出
2
数据范围
对于30%数据,N≤100;
对于60%数据,N≤1000;
对于100%数据,N≤100000,所有权值以及S都不超过1000。

思路
从每个点暴力DFS,如果当前值加上他的儿子的值是否小于S,如果小于,就DFS(儿子),每次当前值等于S时,答案+1

#include<cstdio>
#define rg register
using namespace std;
int n,m,x,y,ans,tot,c[100005];
struct note
{
    int head,next,to;
}a[100005];
void add(int x,int y)
{
    tot++;
    a[tot].to=y;
    a[tot].next=a[x].head;
    a[x].head=tot;
}
void dfs(int now,int s)
{
    if (s==m) ans++;
    for (rg int i=a[now].head;i;i=a[i].next)
    {
        int v=a[i].to;
        if (s+c[v]<=m) dfs(v,s+c[v]);
    }
}
int main()
{
	scanf("%d%d",&n,&m);
	for (rg int i=1;i<=n;i++)
		scanf("%d",&c[i]);
    for (rg int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for (rg int i=1;i<=n;i++)
        dfs(i,c[i]);
    printf("%d\n",ans);
    return 0;
}

T3(时间流逝)

题目描述
生活可以很简单。可以探索水底世界的神秘,也可以去发现奇特新生物,亦或踏上一段新生的旅程。在必须要迎接挑战或跟周围的生物进行生存争夺之前,享受自由的飞翔。此时你会觉得生活是如此美好。
像蛇喜欢吃浮游生物一样(哦,我好像忘记告诉你这个常识),每天,你可以吃一些你周围的基础生物,然后会在你的尾巴上得到一个能量圈。你将会有好多种不同的能量圈,每一个都会被赋予一个能量。你可以拥有多个同种的能量圈,但是对于新得到的能量圈,它的能量不能大于你已拥有的任何一个能量圈。在前面规则的前提下,获得新的能量圈的种类的概率是一样的。一天天过去,你得到越来越多的能量,开始了进化演变。
但是你也有自己的问题,有时你会面对邪恶的果冻鱼。它会追着你咬你,你不得不扔出最小能量值的能量圈然后赶忙逃跑。在这种情况下,你不会有任何的胃口了,因此这天你将不再得到任何能量圈。幸好,当你没有任何能量圈的时候,果冻鱼就算看见你也不会追着你,此时你可以好好地享用美食。
你听说当你的总的能量值超过了某个阈值之后,可以进化成强大模式并能够吃掉果冻鱼。是时候反击了!下面是本题的问题:预计要过多少天你才能进化成强大模式?(第一天默认你没有任何能量圈)
输入
输入包含多个测例。对每个测例会有两行。第一行是一个浮点数P,一个整数T和一个整数N。P是每天遇到果冻鱼的概率,T是阈值。第二行是N个不同的正整数,表示每一种能量圈的能量值。
输出
对于每个测例,输出一行表示预计要过多少天你的能量值能够超过阈值,四舍五入到三位小数。
样例输入
0.5 0 1
1
0.5 1 2
1 2
样例输出
1.000
2.000
数据范围
对于所有数据,0.1≤P≤0.9,1≤T≤50,1≤N≤30。

T4(挖掘机技术哪家强)

题目描述
有人问现实中为什么总是男生追求女生,反过来很少。实际上女生也是想主动追求男生的,但是世俗中对于主动追求男生的女生有种歧视,这样就使得女生不大敢主动追求男生。但是面对喜欢的男生,难道就不出手么?女生只能步步为营,挖坑来引诱男生往里跳。这时候问题就来了,挖掘机技术到底哪家强?
被热血沸腾的广告洗脑了若干天后,Matt终于下定决心,毅然登上了开往泉城的列车,决心寻找生活的希望。
来到布鲁谢特学院后,Matt逐渐地了解了各种型号的挖掘机。在这里我们可以认为有大挖掘机和小挖掘机两种。
今天Matt的任务很简单:首先他要用大挖掘机挖出恰好N单位体积的砂土。由于小挖掘机比较笨拙,它每次挖的砂土体积是固定的。也就是说,设每次挖x单位体积砂土,那么N需要被x整除。在挖出若干堆体积为x的砂土后,Matt需要计算x的“难挖指数”。体积x的“难挖指数”定义如下:对于某个不超过x的体积y,如果x与y的最大公约数为1,那我们认为体积y是“难挖的”,x的“难挖指数”就要加上y。
由于Matt之后还需要用小挖掘机处理被大挖掘机挖出的砂土,他希望知道所有可能的x的难挖指数的和,这样他好估算今天要干多久,不然作为布鲁谢特的高才生,他出门要被笑话的。
输入
第一行一个整数T,表示数据组数。
接下来T行每行一个整数表示N。
输出
对于每个数据输出一行一个整数表示难挖指数的和。
样例输入
3
2
3
4
样例输出
2
4
6
数据范围
对于30%的数据有T<=20,N<=10^4。
对于60%的数据有T<=100,N<=10^7。
对于100%的数据有1<=T<=1000,1<=N<=10^9。
思路
先把题目简单说眀,对于每个N,他的难挖指数为他的因子x的难挖指数的和,而x的难挖指数为从1~x中和x互质的y的总和。
那么我们先对x分析,我们知道如果a和b互质,那么a和a-b也互质(a>b),那么很显然的,x的难挖指数就为x*个数/2。
为什么呢,请看:
设x=5
与5互质的数分别是1、2、3、4,让1和4配对,2和3配对,就可以配出两个5,和就为10
现在的问题就是,个数怎么求以及x怎么快速得出
要求个数,其实就是求欧拉函数,利用欧拉函数的通向公式phi(x)=x *(1-1/p1) * (1-1/p2) * …… * (1-1/pn),p1、p2……pn都是x的质因数
那么x怎么快速得出呢?
我们可以将n分解质因数,然后再组成x就好了

#include<cstdio>
#include<string.h>
#define rg register
#define N 100000
using namespace std;
int t,n,num;
long long ans,x,ol,p[N],c[N],cf[N];
bool b[N];
void js(int now)
{
	if (now>p[0])
	{
		ans+=(x*ol)/2;
		if (x==1) ans++;
		return;
	}
	js(now+1);
	long long save=x,zj=p[now]-1;
	for (rg int i=1;i<=cf[now];i++)
	{
		ol*=zj;
		x*=p[now];
		js(now+1);
		ol/=zj;
		zj*=p[now];
	}
	x=save;
}
int main()
{
	memset(b,true,sizeof(b));
	b[1]=false;	
	for (rg int i=2;i<=N;i++)
		for (rg int j=2;j<=N/i;j++)
			b[i*j]=false;
	num=0;
	for (rg int i=1;i<=N;i++)
	{
		if (b[i])
		{
			num++;
			c[num]=i;
		}
	}
	scanf("%d",&t);
	while (t--)
	{
		ans=0;
		x=1;
		ol=1;
		memset(p,0,sizeof(p));
		memset(cf,0,sizeof(cf));
		scanf("%d",&n);
		for (rg int i=1;i<=num;i++)
		{
			if (n%c[i]==0)
			{
				p[++p[0]]=c[i];
				while (n%c[i]==0)
				{
					cf[p[0]]++;
					n/=c[i];
				}
			}
		}
		if (n>1) 
		{
			p[++p[0]]=n;
			cf[p[0]]=1;
		}
		js(1);
		printf("%lld\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值