题意:
给两个整数n,m
让输出一个长度为n的数组,满足
1
≤
i
<
j
<
k
≤
n
1≤i<j<k≤n
1≤i<j<k≤n
a
i
+
a
j
=
a
k
a_i+a_j=a_k
ai+aj=ak的组数为m组
思路:
考虑如何让符合的三元组数更多,即1,2,3,4,5,6…这样的时候,
a
[
i
]
=
i
a[i]=i
a[i]=i
那每个位置能贡献几组满足题意的三元组呢
计算发现他们的贡献为
0,0,1,2,4,6,9,12…即
(
i
−
1
)
/
2
(i-1)/2
(i−1)/2
意思就是我每增加一个数,它都能贡献
(
i
−
1
)
/
2
(i-1)/2
(i−1)/2
做法:
c
n
t
cnt
cnt记录当前已经有多少组了,每次
c
n
t
+
=
(
i
−
1
)
/
2
cnt+=(i-1)/2
cnt+=(i−1)/2
然后考虑边界,在增加一个数时,发现
c
n
t
+
(
i
−
1
)
/
2
>
m
cnt+(i-1)/2>m
cnt+(i−1)/2>m了,意思就是这个位置不能是
i
i
i了,那应该是多少呢?我们考虑还需要几组,显然还需要
p
=
m
−
c
n
t
p=m-cnt
p=m−cnt组,那添加哪个数刚好增加p组呢
往前找
2
∗
p
2*p
2∗p个数,比如
p
=
5
p=5
p=5,当前要在
i
=
50
i=50
i=50的位置添加数
40,41,42,43,44,
45,46,47,48,49,我们发现这
2
∗
p
2*p
2∗p个数,可以构成p对和都是
40
+
49
=
41
+
48
=
.
.
.
.
.
.
=
89
40+49=41+48=......=89
40+49=41+48=......=89
那
a
[
50
]
=
89
a[50]=89
a[50]=89,是不是就可以增加
p
p
p组
所以
a
[
i
]
a[i]
a[i]应该等于
i
−
1
+
i
−
2
∗
p
i-1+i-2*p
i−1+i−2∗p
这样
m
m
m组已经完成了,如何数组
n
n
n还没有填满,后面的就随便填,保证不会再组成
a
i
+
a
j
=
a
k
a_i+a_j=a_k
ai+aj=ak即可,因为
n
n
n总共才
5000
5000
5000,选一个大点的数开始,每次直接增加
5050
5050
5050,肯定不可能再组成
特判: 如果
c
n
t
!
=
m
cnt!=m
cnt!=m,说明数组填满之后还不够,输出
−
1
-1
−1
代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <map>
#include <queue>
#include <set>
#include <stack>
typedef long long ll;
#define PII make_pair
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int MAXN=2e5+50;
const int inf=0x3f3f3f3f;
const int M=5000*4;
int a[5050];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int cnt=0;
int flag=0;
int k=0;
for(int i=1;i<=n;i++){
if(flag==1){//已经够m个了
a[i]=5e8+k;
k+=5050;
continue;
}
if(cnt+(i-1)/2<=m){
a[i]=i;
cnt+=(i-1)/2;
}
else {
int p=m-cnt;
cnt+=p;
a[i]=i-1+i-2*p;
flag=1;//刚好m个
}
}
if(cnt!=m)printf("-1\n");
else {
for(int i=1;i<=n;i++)
printf("%d%c",a[i],i==n?'\n':' ');
}
return 0;
}