Maths

原题

Maths

Problem Description

Android Vasya attends Maths classes. His group started to study the number theory recently. The teacher gave them several tasks as a homework. One of them is as follows.
There is an integer n. The problem is to find a sequence of integers a 1, …, a n such that for any k from 2 to n the sum a 1 + … + a k has exactly a k different positive divisors. Help Vasya to cope with this task

input

The only line contains an integer n (2 ≤ n ≤ 100 000).

ouput

If there is no such sequence output “Impossible”. Otherwise output space-separated integers a 1, …, a n (1 ≤ a i ≤ 300).

Sample Input

3

Sample Output

1 3 4

题意分析:

题目的意思给出一个n,求一个n项的数列,其中ai>=1 && ai <= 300, 且对于任何 k>1 && k<=n,都有a1 + … + ak的因子数等于ak。

总体思路:

刚开始由于各种原因,我们无法完全理解题意,所以为了验证猜想(和题目意思一样)的正确性,决定先用回溯法,求出满足条件的式子,但输入n = 3后,求出了多个结果(比如1,2,2),导致我们停滞了很久。后来本着死马当活马的态度,强行做了一波。(最后是正确的,本题目有多个答案,并不要求和案例一样
开头我们使用回溯法只是为了验证思路,因为这题的数据过大,所以回溯法显然会超时。
正确是思路应该是利用 “a1 + … + ak的因子数等于ak” 这个特性逆推,即已知当前前k项和为sum,求这个数列前k项的每一项(可以唯一确认此数列)。由于a(k)等于sum的因子数,就可以知道前k-1项和(即sum-a(k)),再由前k-1项和(sum-a(k))推出a(k-1),这样一步步逆推下去,如果最后可以求得sum == 0,就代表这个数字是可以划分的,如果sum是负数就不能划分。
思路清楚之后,我们就观察题目,发现n<=100000这个条件,也就是数列最大是100000项,那么我们只要找到一个数字x,同时x划分的数列有大于或等于100000项,之后根据输入的n,再输出前n项即可。

一:寻找x

思路:利用二分查找,找出一个划分的数列长度大于100000,并且尽可能接近100000的数字即可(为了节约资源),这样对于任何输入的n<=100000程序都可以保证有解。
代码:
#include <iostream>
#include <cmath>
using namespace std;
int f(int x){
    
    
	int t = sqrt(x), i, sum = 0;
	for (i = 1; i <= t; i++){
    
    
		if (x%i == 0){
    
    
			if (x/i == i){
    
    
				sum += 1;
			}else{
    
    
				sum += 2;
			}
		}
	}
	return sum;
}
int main(){
    
    
	int i, t, cnt, left = 2, right = 10000000;
	while (1){
    
    
		i = (left+right)/2;
		t = i;
		cnt = 0;
		while (t > 0){
    
    
			t -= f(t);
			cnt++;
		}
		cout << i << ":" << cnt << endl;
		if (cnt > 100000 && cnt-100000 < 500){
    
    
			cout << "ans: " << i << endl;
			break;
		}
		if (cnt >= 100000){
    
    
			right = i;
		}else{
    
    
			left = i;
		}
	}
	return 0;
}
//解为1589355,可分解为100339项

二:完整程序

思路:上面求解x的代码中,使用的求因子个数的函数f(int x)过于暴力,所以最后一定会超时。所以我使用了另一种求因子数的方法,类似于筛法求素数!

AC代码

#include <cstdio>
#include <cmath>
#define MAXN 1589355
#define N 110010
using namespace std;
int a[MAXN+10] = {
    
    0};
void f(){
    
    
	int i, j, t = sqrt(MAXN)+1;
	for (i = 1; i <= t; i++){
    
    
		for (j = i; i*j <= MAXN; j++){
    
    
			a[i*j]++;
			if (i != j)		a[i*j]++;
		}
	}
}
int main(){
    
    
	f();
	int n, i, j;
	int ans[N], nans = 0, t;
	scanf ("%d", &n);
	
	t = MAXN;
	while (t > 0){
    
    
		ans[nans++] = a[t];	
		t -= a[t];
	}
	
	for (i = nans-1, j = 0; j < n-1 && i > 0; j++, i--){
    
    
		printf ("%d ", ans[i]);
	}
	printf ("%d", ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40735291/article/details/89201436