CF1916D Mathematical Problem

去洛谷看我的博客

思路

很不错的人类智慧题。

拿到以后,完全没有思路,看到数据范围,感觉是什么 n 2 log ⁡ n n^2\log n n2logn 的逆天做法,但是又完全没思路,看后面的题感觉没希望,就在这道题死磕。

先打了个暴力程序,发现平方数太多,没什么规律,就拿了个 map 统计一下那些出现数字方案拥有的平方数比较多

程序如下:

#include<bits/stdc++.h>
using namespace std;
multiset<int>s;
map<multiset<int>,int>mp;
int main()
{
	for(int i=1;i<=200000;++i)
	{
		long long k=1ll*i*i;
		if(k<100000000) continue;//此程序是九位数的情况,想试其他情况的就改这里的值即可
		if(k>999999999) break;
		while(k) s.insert(k%10),k/=10;
		++mp[s],s.clear();
	}
	for(auto i:mp)
	{
		if(i.second>=9)//这里也要改
		{
			for(auto j:i.first)
			{
				cout<<j<<" ";
			}
			puts("");
		}
	}
	return 0;
}

先试一试五位数的情况,发现下面的数字组合都可以存在五个以上的平方数,除了样例给的还有一组。

  • 0 0 1 6 9
  • 1 3 4 6 8

再试一试七位数的情况,发现符合条件的数字组合更多了。

  • 0 0 0 0 1 6 9
  • 0 0 1 3 4 6 8
  • 0 1 2 4 5 6 9
  • 0 1 4 5 6 7 8
  • 1 2 3 4 4 5 6
  • 1 2 3 4 4 8 9

一看,发现了一个很重要的规律,都有 0   ⋯   0   1   6   9 0~ \cdots ~0 ~1 ~6 ~9 0  0 1 6 9

所以猜测所有情况都可以由若干个 0 0 0 1   6   9 1~6~9 1 6 9 构成。

再试一试九位数,发现也是如此。

于是,改了改暴力程序,让程序输出符合条件的平方数,如下:

#include<bits/stdc++.h>
using namespace std;
multiset<int>s;
map<multiset<int>,int>mp;
int main()
{
	multiset<int>tmp;
	tmp.insert(0),tmp.insert(0),tmp.insert(0),tmp.insert(0),tmp.insert(0),tmp.insert(0),tmp.insert(1),tmp.insert(6),tmp.insert(9);//同样是九位数的程序,其他情况注意更改参数
	for(int i=1;i<=200000;++i)
	{
		long long k=1ll*i*i;
		if(k<100000000) continue;
		if(k>999999999) break;
		while(k) s.insert(k%10),k/=10;
		if(s==tmp) printf("%lld\n",1ll*i*i);
		s.clear();
	}
	return 0;
}

先试一试五位数的,发现程序给的是:

10609
16900
19600
61009
90601
96100

研究了一下,发现首先又 1690 ⋯ 1690\cdots 1690 1960 ⋯ 1960\cdots 1960 9610 ⋯ 9610\cdots 9610,这三个很显然,都是 169 169 169 196 196 196 961 961 961 乘以了 1 0 k 10^k 10k,其中 k k k 为偶数,所以一定是平方数。

剩下的就是 10 ⋯ 60 ⋯ 90 ⋯ 10\cdots60\cdots90\cdots 106090,也就是 169 169 169 1 1 1 6 6 6 之间和 6 6 6 9 9 9 之间插入相同数量的零,再在后面放若干个零构成的,首先因为插入的零是偶数,并且总数字个数是奇数,再加上有 169 169 169 三个数字,所以后面的零一定是偶数个,所以后面加的一定正确,只需要验证 10 ⋯ 60 ⋯ 9 10\cdots60\cdots9 10609 是否一定正确即可,发现就是 10 ⋯ 3 10\cdots3 103 的平方,所以一定正确。

那么同理 961 961 961 1 1 1 6 6 6 之间和 6 6 6 9 9 9 之间插入相同数量的零,再在后面放若干个零构成的数也一定是平方数,也是正确的。

使用暴力程序在七位数和九位数验证,发现是正确的。

再计算一下我们发现了多少个平方数了,在其中插入的零可以是 [ 0 , n − 1 2 − 1 ] [0,\frac{n-1}2-1] [0,2n11] 个,一共有 n − 1 2 \frac{n-1}2 2n1 个, 169 169 169 961 961 961都可以,一共有 n − 1 n-1 n1 个,再加上 1960 ⋯ 1960\cdots 1960 的一个,刚好 n n n 个。

其实发现还有形如 61009 61009 61009 之类的数也满足条件,但是我们已经不需要了。

根据上面发现的构造方案可以很轻松的写出程序。

AC code

#include<bits/stdc++.h>
using namespace std;
long long T,n,a,sum,num;
int main()
{
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld",&n);
		if(n==1){puts("1");continue;}//注意特判n=1
		printf("169");
		for(int i=4;i<=n;++i) printf("0");
		puts("");
		printf("961");
		for(int i=4;i<=n;++i) printf("0");
		puts("");
		printf("196");
		for(int i=4;i<=n;++i) printf("0");
		puts("");
		for(int i=1;i<n/2;++i)
		{
			printf("1");
			for(int j=1;j<=i;++j) printf("0");
			printf("6");
			for(int j=1;j<=i;++j) printf("0");
			printf("9");
			for(int j=3+2*i;j<n;++j) printf("0");
			puts("");
			printf("9");
			for(int j=1;j<=i;++j) printf("0");
			printf("6");
			for(int j=1;j<=i;++j) printf("0");
			printf("1");
			for(int j=3+2*i;j<n;++j) printf("0");
			puts("");
		}
	}
	return 0;
}
  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数学分析是现代数学的一个重要分支,也是数学基础中的一门重要课程。它主要研究极限、连续、导数、微分、积分等概念和性质,是数学的一种精密且严谨的推理工具。 数学分析的研究对象包括实数、复数、函数以及它们之间的关系。通过对函数的性质和行为的深入研究,数学分析为其他数学分支提供了坚实的数学基础。例如,在微积分中,我们使用分析的方法来研究函数的极限、导数和积分,从而得到了计算斜率、求曲线面积和计算物体的速度与加速度等重要工具和概念。 除了应用于物理学、工程学和计算机科学等实际领域,数学分析也是数学内部的一个重要分支。数学分析中的严密证明和推理方法对于数学的发展起到了关键的作用。许多数学定理和概念的证明都直接或间接地依赖于数学分析的方法。 数学分析学习的过程中,我们需要掌握一些基本概念和技巧,例如收敛性、连续性、导数运算规则和积分运算等。在解决实际问题时,我们还需要运用数学分析的思维方式和技巧,从复杂的问题中找到简单的解决方法。 总之,数学分析是一门重要且广泛应用的数学学科,它通过研究极限、连续、导数、微分、积分等概念和性质,为其他数学分支提供了坚实的数学基础,并在实际领域和数学发展中发挥着重要的作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值