其他分享
首页 > 其他分享> > 10.5 a.m.小结

10.5 a.m.小结

作者:互联网

T1:问题 A: 反素数 Antiprime

题目描述

如果一个大于等于 1 的正整数 n,满足所有小于 n 且大于等于 1 的所有正整数的约数个数都小于 n 的约数个数,则 n 是一个反素数。譬如:1, 2, 4, 6, 12, 24,它们都是反素数。

请你计算不大于 n 的最大反素数。

输入

一行一个正整数 n。

输出

只包含一个整数,即不大于 n 的最大反素数。

样例输入

1000

样例输出

840

提示


【数据范围与提示】

对于 10% 的数据,1≤n≤103 ;


对于 40% 的数据,1≤n≤10^6

对于 100% 的数据,1≤n≤2×10^9

题解:

 首先可以得知,每一个因子的次数不宜太多,不过2的次数可以较多。显然,可以通过枚举质数的系数来枚举一些数,然后用桶的思想装起来,最后从上往下找到一个次数最高的数,然后作为答案输出即可。所以枚举时宁愿多取数,也不要漏答案。

参考代码:

#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
int n,prime[200]={0,2,3,5,7,11,13,17,19,23,29};
LL lg[2000],sum=1ll,lei[200010];
void dfs(int k)
{
	LL st=1ll;
	for(int i=1;i<=(k==1?31:5);i++)
	{
		st*=prime[k];
		if(st*sum<=n)
		{
			sum*=st;
			lg[k]=i;
			dfs(k+1);
			lg[k]=0;
			sum/=st;
		}
		else
		{
			LL pt=1ll;
			for(int j=1;j<k;j++)
			pt*=(lg[j]+1ll);
			if(lei[pt]>sum) lei[pt]=sum;
			break;
		}
	}
}
int main()
{
	memset(lei,127/3,sizeof(lei));
	scanf("%d",&n);
	for(int i=1;i<=30;i++) lg[i]=1ll;
	dfs(1);
	for(int i=20000;i>=1;i--)
	{
		if(lei[i]<=n)
		{
			printf("%d",lei[i]);
			break;		
		}
	} 
	return 0;
}

T2:问题 B: 五指山

题目描述

大圣在佛祖的手掌中。

我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,⋯,n−1,而大圣每次飞的距离为 d。现在大圣所在的位置记为 x,而大圣想去的地方在 y。要你告诉大圣至少要飞多少次才能到达目的地。

输入

有多组测试数据。

第一行是一个正整数 T,表示测试数据的组数;
每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。

注意孙悟空的筋斗云只沿着逆时针方向翻。

输出

对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。如果无论翻多少个筋斗云也不能到达,输出 Impossible。

样例输入

2
3 2 0 2
3 2 0 1

样例输出

1
2

提示

【数据范围与提示】

对于全部数据,2<n<10^9 ,0<d<n,0≤x,y<n。

题解:

这道题可以转化成同余的问题。由于大圣只能逆时针飞行,所以路线已经固定。如果数据不大,完全可以用模拟来做……因此就是将原问题完全变成求一个同余方程的x、y。这一点用exgcd就可以解决。注意n也要缩小gcd倍。

参考代码:

#include<cstdio>
#define LL long long
using namespace std;
LL n,d,x1,y1,t;
LL exgcd(LL a,LL b,LL & x,LL & y)
{
	if(b==0)
	{
		x=1;y=0;return a;
	}
	LL d=exgcd(b,a%b,x,y);
	LL z=x;x=y;y=z-(a/b)*y;
	return d;
}
int main()
{
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld%lld%lld",&n,&d,&x1,&y1);
		LL qp=(y1-x1+n)%n;
		LL x,y;
		LL gcd=exgcd(d,n,x,y);
		n=n/gcd;
		if((y1-x1)%gcd!=0) printf("Impossible\n");
		else
		{
			if(x*(y1-x1)%gcd!=0) printf("Impossible\n");
			else
			{
				x=((x*(y1-x1)/gcd)%n+n)%n;
				printf("%lld\n",x);		
			}
		}
	}
	return 0;
}

T3:问题 C: Matrix Power Series

题目描述

给定n×n矩阵A和正整数k,求和S=A^1+A^2+\cdots +A^k

输入

输入只包含一个测试用例。
第一行输入包含三个正整数n,k和m。
接下来n行,每行包含n个非负整数(均不超过32,768),用以描绘矩阵A。

输出

按与描述矩阵A相同的方式,输出将S中所有元素对m取模后得到的矩阵。

样例输入

2 2 4
0 1
1 1

样例输出

1 2
2 3

提示

【数据范围】

1≤n≤30,

1≤k≤10^6,

1≤m<10^4

题解:

        对于这道题,显然会用到矩阵加速递推。刚开始考虑推导通项公式,结果发现分母会带矩阵。由于不知道这样如何处理,就想办法用其他方法来表示一个普通的等比数列。之前有一道题带给了我思路,即已知一个数X=a_{1}^{p_{1}^{}}\times a_{2}^{p_{2}^{}}\times\cdots\times a_{k}^{p_{k}^{}}(a1、a2、……ak均为质数),那么X的因子个数为:(p_{1}^{}+1)\times (p_{2}^{}+1)\times\cdots\times (p_{k}^{}+1)。证明方式就是把括号全部拆开,发现每一个因子都能找到。由此我想到了一种特殊的构造方式,对于一个数k,如果恰好k=2_{}^{p} -1,那么从1到k的等比数列之和可以表示为(1+A_{}^{1})\times (1+A_{}^{2})\times(1+A_{}^{4})\times(1+A_{}^{8})\cdots\times(1+A_{}^{2^{p-1}})-1,注意,最后是2的p-1次方。把括号打开就能得到所有需要求的数。把这个公式延伸到矩阵中,1就是单位矩阵,从左上到右下一条对角线为1,其余全部为0。顾名思义,任意矩阵B与单位矩阵相乘就是本身。-1就是-单位矩阵。此时就可以用O(logn)的效率解决A_{}^{2^{p}}的值,然后求出答案。

        现在来考虑k一般化。此时可以采用倍增的思想,先把能求的求了。即:先求出最大能求出的连续等比的和,就用上述的公式以logn的效率解决。此时来看剩下的,把这些单独看成新的一段,也就是说提取公因式,让最小的一个次数为1,自然又变成了一个相同的问题,再次用公式解决能解决的,最后剩下的再提取公因式……提取的公因式如何求?直接用快速幂解决。因为有些特殊的如AA^2A^4等很可能会重复出现,因此这些值可以预处理出来(预处理就不要用快速幂了,直接由2个上一项加起来就能得到这一项)。注意,为了问题的简便,此处把A的2的n次方处理出来后,要加上一个单位矩阵,就减少了+1的步骤。

        可以采用2个while循环实现倍增的过程,最外层为rest,表示还剩下多少项需要处理,每次新一轮循环需要初始化。第二个枚举最多能到2的多少次方,同时每枚举一次,就累乘一次答案,定位ret1。同时还要用p记录枚举到2的第几个次方,直接找记忆化的值,pre表示已经解决的项数(其实可以不用,用rest就行,不过为了思路清晰,还是写上),用于上述讲到的公因式的处理,要用快速幂。讲到快速幂就需要注意:转移矩阵是输入的矩阵,不能+1,这一点要格外注意。而且每次快速幂的时候,单位矩阵和转移矩阵都要初始化。用qpow能处理出ret。最后每一次累加ret*ret1就能够得到ans答案。(代码中的UP数组为中转数组)

参考代码:

#include<cstdio>
#define LL long long
using namespace std;
LL n,m,k,rest,t,pre,A[31][31][35],p;
LL CH[31][31],ret[31][31],TR[31][31],st[31][31];
LL UP[31][31],ret1[31][31],ans[31][31];
void qpow(LL z)
{
	for(int i=1;i<=n;i++)
	{
		ret[i][i]=1ll;
		for(int j=1;j<=n;j++)
		CH[i][j]=st[i][j];
	}
	while(z)
	{
		if(z&1) 
		{
			for(int i=1;i<=n;i++)
			  for(int j=1;j<=n;j++)
			    for(int h=1;h<=n;h++)
				  TR[i][j]=(TR[i][j]+ret[i][h]*CH[h][j])%m;
			for(int i=1;i<=n;i++)
			  for(int j=1;j<=n;j++)
			  {
			  	ret[i][j]=TR[i][j];
			  	TR[i][j]=0;
			  }
		}
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=n;j++)
		    for(int h=1;h<=n;h++)
		      TR[i][j]=(TR[i][j]+CH[i][h]*CH[h][j])%m;
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=n;j++)
		    {
		    	CH[i][j]=TR[i][j];
		    	TR[i][j]=0;
			}
		z/=2ll;
	}
}
int main()
{
	scanf("%lld%lld%lld",&n,&k,&m);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	{
		scanf("%lld",&A[i][j][0]);
		st[i][j]=A[i][j][0];
	}
	t=1ll;p=1ll;
	while(t*2ll-1ll<=k)
	{
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=n;j++)
		  	for(int h=1;h<=n;h++)
		      A[i][j][p]=(A[i][j][p]+A[i][h][p-1]*A[h][j][p-1])%m;
		p++;t*=2ll;
	}
	for(int i=0;i<p;i++)
	  for(int j=1;j<=n;j++)
	    A[j][j][i]++;
	rest=k;
	while(rest)
	{
		for(int i=1;i<=n;i++)
		ret1[i][i]=1;
		t=1ll;p=1ll;
		while(t*2ll-1ll<=rest)
		{
			for(int i=1;i<=n;i++)
			  for(int j=1;j<=n;j++)
			    for(int h=1;h<=n;h++)
			      UP[i][j]=(UP[i][j]+ret1[i][h]*A[h][j][p-1])%m;
			for(int i=1;i<=n;i++)
			  for(int j=1;j<=n;j++)
			    {
			    	ret1[i][j]=UP[i][j];
			    	UP[i][j]=0;
				}
			p++;t*=2ll;
		}
		for(int i=1;i<=n;i++)
		ret1[i][i]=(ret1[i][i]-1+m)%m;
		qpow(pre);
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=n;j++)
		    for(int h=1;h<=n;h++)
		      UP[i][j]=(UP[i][j]+ret1[i][h]*ret[h][j])%m;
		for(int i=1;i<=n;i++)
		  for(int j=1;j<=n;j++)
		    {
		    	ans[i][j]=(ans[i][j]+UP[i][j])%m;
		    	UP[i][j]=ret1[i][j]=ret[i][j]=0;
			}
		pre+=t-1ll;
		rest-=t-1ll;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		printf("%lld ",ans[i][j]);
		printf("\n");
	}
	return 0;
}

T4:问题 D: Xiao 9*大战朱最学

题目描述

自从朱最学搞定了QQ农场以后,就开始捉摸去QQ牧场干些事业,不仅在自己的牧场养牛,还到阿九的牧场放牛!
阿九很生气,有一次朱最学想知道阿九牧场奶牛的数量,于是阿九想狠狠耍朱最学一把。
举个例子,假如有16头奶牛,如果建了3个牛棚,剩下1头牛就没有地方安家了。
如果建造了5个牛棚,但是仍然有1头牛没有地方去,然后如果建造了7个牛棚,还有2头没有地方去。
你作为阿九的私人秘书理所当然要将准确的奶牛数报给阿九,你该怎么办?
 

输入

第一行包含一个整数n表示建立牛棚的次数。
接下来n行,每行两个整数ai,bi, 表示建立了ai个牛棚,有bi头牛没有去处。
你可以假定不同ai之间互质。

输出

输出包含一个正整数,即为阿九至少养奶牛的数目。

样例输入

3
3 1
5 1
7 2

样例输出

16

提示

【数据范围】

1≤n≤10,

1≤ai,bi≤1200000

题解:

这道题就是“曹冲养猪”,一模一样,样例都没变,直接用exgcd解决即可。

参考代码:

#include<cstdio>
#define LL long long
using namespace std;
int n;LL a1,b1,a2,b2;
LL exgcd(LL a,LL b,LL & x,LL & y)
{
	if(b==0)
	{
		x=1;y=0;return a;
	}
	LL d=exgcd(b,a%b,x,y);
	LL z=x;x=y;y=z-(a/b)*y;
	return d;
}
int main()
{
	scanf("%d",&n);
	scanf("%lld%lld",&a1,&b1);
	for(int i=1;i<n;i++)
	{
		scanf("%lld%lld",&a2,&b2);
		LL x,y,gcd;
		gcd=exgcd(a1,a2,x,y);
		x=((x*(b2-b1)/gcd)%a2+a2)%a2;
		b1=((a1*x+b1)%(a1*a2)+a1*a2)%(a1*a2);
		a1=a1*a2;
	}
	printf("%lld",b1);
	return 0;
}

T5:问题 F: Goldbach's Conjecture

题目描述

哥德巴赫猜想:任何大于 4 的偶数都可以拆成两个奇素数之和。 比如:
你的任务是:验证小于 10^6  的数满足哥德巴赫猜想。

输入

多组数据,每组数据一个 n。

读入以 0 结束。

输出

对于每组数据,输出形如 n = a + b,其中 a,b 是奇素数。若有多组满足条件的 a,b,输出 b-a 最大的一组。
若无解,输出 Goldbach's conjecture is wrong.。

样例输入

8
20
42
0

样例输出

8 = 3 + 5
20 = 3 + 17
42 = 5 + 37

提示

【数据范围与提示】

对于全部数据,6≤n≤10^6 。

题解:

凭感觉我就知道输出不可能是不可能输出的!(-……-)

首先筛素数,1000就行了。然后题目要求输出差最大的一组,因此直接从最小的奇素数开始搜,然后看n-prime[j]是不是也是一个质数,直接看mf的值是不是等于本身即可。找到一个就直接输出,自然能够满足题目要求。

参考代码:

#include<cstdio>
using namespace std;
int prime[1000100],mf[1000100],cnt=0,n;
int main()
{
	for(int i=2;i<=1000000;i++)
	{
		if(!mf[i])
		{
			mf[i]=i;
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=1000000;j++)
		{
			mf[i*prime[j]]=prime[j];
			if(mf[i]==mf[i*prime[j]]) break;
		}
	}
	while(1)
	{
		scanf("%d",&n);
		if(n==0) break;
		for(int i=2;i<=cnt;i++)
		{
			if(mf[n-prime[i]]==n-prime[i])
			{
				printf("%d = %d + %d\n",n,prime[i],n-prime[i]);
				break;
			}
		}
	}
	return 0;
}

 

标签:输出,10.5,int,矩阵,LL,样例,小结,31
来源: https://blog.csdn.net/Penguin_Wang/article/details/120617057