P6860 象棋与马

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

【LGR-078】洛谷 10 月月赛 II T4
题目链接


D e s c r i p t i o n Description Description

一张无限大的网格,若从 ( x , y ) (x,y) (x,y)出发,每一步可以类似于马一样移动,长度分别为 a , b a,b a,b(对于经常提起的中国象棋中的马的话,则有 a = 1 , b = 2 a=1,b=2 a=1,b=2 a = 2 , b = 1 a=2,b=1 a=2,b=1),若能到达这个网格中的任意一节节点,则 p ( a , b ) = = 1 p(a,b)==1 p(a,b)==1

∑ i = 1 n ∑ j = 1 n p ( i , j ) \sum _{i=1}^n\sum _{j=1}^n p(i,j) i=1nj=1np(i,j)

数据范围:
20 % , n ≤ 3000 20\%,n\leq 3000 20%,n3000
50 % , n ≤ 1 0 7 50\%,n\leq 10^7 50%,n107
100 % , n ≤ 1 0 11 100\%,n\leq 10^{11} 100%,n1011


S o l u t i o n Solution Solution
20 p t s 20pts 20pts

能从 ( x , y ) (x,y) (x,y)移动到任意一个格子的充要条件是它能位移到 ( x + 1 , y ) (x+1,y) (x+1,y) ( x , y + 1 ) (x,y+1) (x,y+1)
也就是要找出一种位移方案,使得这么多步后,位移到一个格子 ( x + m a + n b , y + e a + f b ) (x+ma+nb,y+ea+fb) (x+ma+nb,y+ea+fb),使得 m a + n b = 1 ma+nb=1 ma+nb=1 e a + f b = 0 ea+fb=0 ea+fb=0,对于前者,我们很容易得到 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1

对于后者,略加思索,可以发现: a , b a,b a,b不能同时为奇数

如此这般,我们预处理3000以内的这样的 a , b a,b a,b,为了节省效率,我们只算 a > b a>b a>b的,最后再乘二即可

时间复杂度: O ( n 2 l o g n ) O(n^2logn) O(n2logn) 实际上常数较小,可以拿到 20 p t s 20pts 20pts

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;int Gcd[3010][3010],k,T;
ULL sum,s[3010],n;
inline int gcd(int x,int y)
{
	if(Gcd[x][y]) return Gcd[x][y];//似乎没有多大用处的记忆化
	return Gcd[x][y]=y?gcd(y,x%y):x;
}
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
signed main()
{
	for(register int i=1;i<=3000;i++)
	{
		for(register int j=1;j<=i;j++)
		{
			if((i&1)&&(j&1)) continue;
			sum+=gcd(i,j)==1;
		}
		s[i]=sum;
	}
	T=read();
	while(T--)
	{
		n=read();
		printf("%llu\n",s[n]*2);
	}
}
50 p t s 50pts 50pts

假设我们已经确定了 a a a,考虑怎样的 b b b是合法的
刚刚我们已经得出了 a , b a,b a,b互质,但又有 a , b a,b a,b不同时为奇数这个限制

那么假设 a a a是一个偶数,则它的贡献是不大于它且与它互质的自然数,即 φ ( a ) \varphi(a) φ(a)
假设 a a a是一个奇数,则它的贡献是不大于它且与它互质的偶数,这貌似很难办,考场的时候我是推规律推出它为 φ ( 2 a ) 2 \frac {\varphi(2a)}2 2φ(2a)【有能力证明的dalao可以在下方提一下】

如此,我们只需要线性筛出 2 × 1 0 7 2\times 10^7 2×107内的 φ \varphi φ,求个前缀和即可

时间复杂度: O ( n ) O(n) O(n),可以拿到 50 p t s 50pts 50pts

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define ULL unsigned long long
using namespace std;int T,phi[20000010],prime[2000010],vis[20000010],m;
ULL n,s[10000010];
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void prework()
{
	phi[1]=1;
	for(register int i=2;i<=20000000;i++)
	{
		if(vis[i]==0) {vis[i]=i;prime[++m]=i;phi[i]=i-1;}
		for(register int j=1;j<=m&&prime[j]*i<=20000000;j++)
		{
			if(prime[j]>vis[i]) break;
			vis[i*prime[j]]=prime[j];
			phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
		}
	}
	return;
}
signed main()
{
	prework();
	for(register int i=1;i<=1e7;i++)
	{
		if(i&1) s[i]=phi[i*2]/2;
		else s[i]=phi[i];
		s[i]+=s[i-1];
	}
	T=read();
	while(T--)
	{
		n=read();
		printf("%llu\n",s[n]*2);
	}
}
100 p t s 100pts 100pts

基于 50 p t s 50pts 50pts的思路,多利用些欧拉函数的性质即可

i i i是奇数, φ ( 2 i ) = φ ( i ) \varphi(2i)=\varphi(i) φ(2i)=φ(i)
i i i是偶数, φ ( 2 i ) = 2 φ ( i ) \varphi(2i)=2\varphi(i) φ(2i)=2φ(i)

i i i为偶数时, w i = φ ( i ) w_i=\varphi(i) wi=φ(i)
i i i为奇数时, w i = φ ( 2 i ) 2 = φ ( i ) 2 w_i=\frac{\varphi(2i)}2=\frac{\varphi(i)}2 wi=2φ(2i)=2φ(i)

S ( n ) S(n) S(n)表示答案

S ( n ) = 2 ∑ i = 1 n w i S(n)=2\sum_{i=1}^n w_i S(n)=2i=1nwi,那么 S ( n ) S(n) S(n)就等于所有偶数的 φ \varphi φ和的两倍+所有奇数的 φ \varphi φ的和

我们可以直接用杜教筛算出奇数+偶数的 φ \varphi φ和(即 φ \varphi φ的前缀和),然后考虑补上没算的偶数的贡献,这一段的贡献即为 S ( ⌊ n 2 ⌋ ) S(\lfloor \frac n2\rfloor) S(2n),递归处理即可,层数显然是 l o g log log层的

时间复杂度: O ( n 2 3 l o g n ) O(n^{\frac 2 3}log n) O(n32logn),可以通过本题


C o d e Code Code
#include<map>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ULL unsigned long long
using namespace std;
ULL T,prime[2000010],vis[20000010],m,n,phi[20000010],s[20000010];
map<ULL,ULL>Sphi; 
inline ULL read()
{
	char c;ULL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void prework()
{
	phi[1]=1;
	for(register int i=2;i<=20000000;i++)
	{
		if(vis[i]==0) {vis[i]=i;prime[++m]=i;phi[i]=i-1;}
		for(register int j=1;j<=m&&prime[j]*i<=20000000;j++)
		{
			if(prime[j]>vis[i]) break;
			vis[i*prime[j]]=prime[j];
			phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
		}
	}
	for(register int i=1;i<=20000000;i++) 
	{
		if(i&1) s[i]=phi[i*2]/2;
		else s[i]=phi[i];
		s[i]+=s[i-1];
		phi[i]+=phi[i-1];
	}
	return;
}
inline ULL Getphi(ULL n)
{
	if(n<=20000000) return phi[n];
	if(Sphi[n]) return Sphi[n];
	ULL res=0;
	if(n%2==0) res=n/2*(n+1);
	else res=(n+1)/2*n;//这一段要这样子弄一弄,不然可能会爆
	for(ULL l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		res-=(r-l+1)*Getphi(n/l);
	}
	return Sphi[n]=res;
}
inline ULL S(ULL n)
{
	if(n<=1) return 0;
	return Getphi(n)+S(n/2);
}
signed main()
{
	prework();
	T=read();
	while(T--)
	{
		n=read();
		printf("%llu\n",S(n));
	}
}
基于STM32F407,使用DFS算法实现最短迷宫路径检索,分为三种模式:1.DEBUG模式,2. 训练模式,3. 主程序模式 ,DEBUG模式主要分析bug,测量必要数据,训练模式用于DFS算法训练最短路径,并将最短路径以链表形式存储Flash, 主程序模式从Flash中….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值