题目地址
https://codeforces.com/problemset/problem/1409/C
题目描述
给定 n , x , y n,x,y n,x,y,请构造出一个序列 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an,使 x , y ∈ { a i } x,y \in \{a_i\} x,y∈{ai},且排序后 a 2 − a 1 = a 3 − a 2 = ⋯ = a n − a n − 1 a_2-a_1=a_3-a_2=\cdots=a_n-a_{n-1} a2−a1=a3−a2=⋯=an−an−1,并且使 max i = 1 n a i \max_{i=1}^n a_i maxi=1nai 最小。请求出这个序列。
解题思路
根据题目描述我们可以得知,要生成一个数量为 n n n的等差数列,数列中要包含 x , y x,y x,y,并且要求数列中的第1项大于0,最后一项最小。
首先要找到公差
d
d
d,数列中要包含
x
,
y
x,y
x,y,l。因此枚举1
到y-x
中能整除y-x
数即可。
对于不同的公差 d d d,设在公差 d d d下 x x x到 y y y有 k k k项。考虑下面几种不同的情况:
- 当 k = n k=n k=n,直接输出答案, a 1 = x , a n = y a_1=x,a_n=y a1=x,an=y
- 当 k > n k>n k>n,直接跳过此公差
- 当 k < n k<n k<n,设 x x x之前在公差 d d d下,且大于 0 0 0有 p r e pre pre 项:
3.1 : p r e = 0 pre=0 pre=0时, a 1 = x a_1=x a1=x;
3.2 :当 p r e + k < = n pre+k<=n pre+k<=n, a 1 a_1 a1为大于0的第 1 1 1项;
3.3 : 当 p r e + k > n pre+k>n pre+k>n, x x x前的项数就不能全部取完,只能前 x x x前的 n − k n-k n−k项;
得到 a 1 a_1 a1后,计算出 a n a_n an比较下大小即可
参考代码
#include <iostream>
using namespace std;
int main(){
int t,n,x,y;
cin>>t;
while ( t-- ) {
cin>>n>>x>>y;
int temp = y-x;
int ans=x+(n-1)*temp; //数列最后一项
int d=temp; //公差
//枚举所有可能的公差
for ( int i=1; i <= temp; i++ ) {
if( temp%i == 0 ) {
//x和y之间的项数
int num = temp/i + 1;
if( num > n ) continue;
if( num == n ) {
ans = y;
d = i;
break;
}
//x为首项
if( ans > x+(n-1)*i ){
ans = x+(n-1)*i;
d=i;
}
//计算x之前的项数
int num_pre = 0;
num_pre = x / i;
if( x%i == 0 ) num_pre = x/i - 1;
if(num_pre<=0) continue;
int a1,an;
//判断x之前的项是否超过输出的项
if( num_pre + num <= n){
a1= x- ( num_pre )*i;
an= a1 + (n-1)*i;
}else{
a1= x- ( n-num )*i;
an= a1 + (n-1)*i;
}
if(an<ans){
ans=an;
d=i;
}
}
}
ans=ans-(n-1)*d;
for ( int i=0; i<n-1;i++)
cout<<ans+i*d<<" ";
cout<< ans+ d*(n-1)<<endl;
}
return 0;
}
总结
分析问题时,由题目给出的限制条件,在纸上先列出所有可能的情况,对其分类讨论;分类讨论时,先在大的方向进行分类,然后在大分类的基础再继续进行细分。比如这道题是以 x x x和 y y y之间在公差 d d d下能产生多少个数列项进行分类,在此基础上再继续细分下去。