CodeForces - 803C

解决一个数学问题,构造一个长度为k的严格递增数组,使得这些数的最大公约数尽可能大,同时它们的和为n。若不存在这样的数组,则输出-1。本文详细介绍了问题的分析过程及高效的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C. Maximal GCD
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given positive integer number n. You should create such strictly increasing sequence of k positive numbers a1, a2, ..., ak, that their sum is equal to n and greatest common divisor is maximal.

Greatest common divisor of sequence is maximum of such numbers that every element of sequence is divisible by them.

If there is no possible sequence then output -1.

Input

The first line consists of two numbers n and k (1 ≤ n, k ≤ 1010).

Output

If the answer exists then output k numbers — resulting sequence. Otherwise output -1. If there are multiple answers, print any of them.

Examples
input
Copy
6 3
output
Copy
1 2 3
input
Copy
8 2
output
Copy
2 6
input
Copy
5 3
output
Copy
-1

原题是这个,在昨天和河大的联赛里给改成了中文,难度降低了很多(ಥ _ ಥ)中文学的还不怎么样呢 再去理解英语那些拐弯抹角滴是真滴心塞塞啊 

题意:

请构造一个长度为k的严格递增的数组,要求这k个数的最大公约数尽可能的大,且这k个数的和为n

如果不存在这样的数组请直接输出 -1.

Input

输入两个正整数 n 和 k (1 ≤ n, k ≤ 1010).

Output

如果答案存在则输出答案: k 个数,用空格间隔.如果有多个答案满足条件,输出其中一种情况就行 否则就输出 -1.

刚一看题就很懵逼 其实细细分析 还没很难ヾ(。 ̄□ ̄)ツ゜゜゜额...也不知道谁给我的勇气说不难哈哈哈

其实大概就可以用下面的公式来表达:q表示公约数,a1,a2...ak表示k个数


上面的式子也可以化简为:


题目上要求最大的公约数所以a1+a2+a3+~+ak的最小值是(1+2+~+(k-1)+k)的情况;

即:

当他们之和小于n/q时,我们可以把k的值一直往后加,直到他们的和等于n/q,于是就有了下面的代码:

#include<cstdio>
long long n,k;
int main()
{
	while(scanf("%lld %lld",&n,&k)!=EOF)
	{
		long long sum,sum1,s=1;
		int flag=0;
		sum1=sum=k*(k+1)/2;
		if(sum>n)
		{
			flag=1;
		}else
		{
			while(n%sum)
			{
				sum++;
			}
			s=n/sum;
		}
		if(flag)
		{
			printf("-1\n");
		}	
		else
		{
			for(long long i=1;i<k;i++)
			{
				printf("%lld ",s*i);
			}
			printf("%lld\n",s*(k+sum-sum1));
		}
	}
}

但是...因为题目中的数据比较大,如果循环遍历ak的值+1,当差值很大时,时间会超限:

while(n%sum)//sum表示a1~ak的总和
{
    sum++;
}
s=n/sum;//求出来满足条件的最大公约数

就是这一小点,不要小看它,真的很费时间...我百思不得其解,于是我看了题解..大概似懂非懂。

既然直接求ak的话会超时,我们已经确定了a1~ak-1的和,那么我们可以找出来最大的公约数(因为最大公约数的求法阔以优化ヾ(。 ̄□ ̄)ツ゜゜゜只需要O(sqrt(n))的时间复杂度),

套用就可以求出来m,

最大公约数的求法:

for(long long i=1;i<=sqrt(n);i++)
    {
	    if(n%i==0)//如果==0,i是约数,n/i也是约数,
	    {
	        if(i>=(1+k)*k/2)//判断i是否大于等于1~k的和,如果大于等于表示i满足a1~ak和的情况
		{
			q=n/i;//所以公约数是n/i;
			break;//第一个大于(1+~+k)值的它的公约数一定是最大的!!!
		}
                else if(n/i>=(1+k)*k/2)判断n/i是否大于等于1~k的和,同上的思想
                     q=i;//但是n/i不一定是最小的,所以不break;
            }
     }

如果想明白的话还是很好懂的,

为什么是循环只遍历到sqrt(n)?


假如n=21,如果1是n的约数,那么n/1=21也是它的约数,同理,3是n的约数,n/3=7也是它的约数,一直到sqrt(n的时候,两个约数是相等的,sqrt(n之后就相当于是从1~sqrt(n再遍历一遍,(φ(≧ω≦*)♪多想几遍你就能懂了~加油)

2.两个判断条件,前面我们说到约数问题,n%i==0表示i,n/i都是n的约数,前面我们说了(1+2+~+k)<=n,它是满足条件的最初的一个状态,如果他等于n话直接可以输出,如果不的话,我们就要找出一个a1+~+ak的值大于(1+2+~+k)的。((ಥ _ ಥ)可能说的还不是很清楚,但大概就是这样,再多想想,多想想,代码我给的注释也很清楚,两者结合一下哈ヾ(=゚・゚=)ノ喵♪)

引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.youkuaiyun.com/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值