前言
没有在题解区发现类似做法
大部分题解都是从大到小枚举,但是从小到大也有一种做法
证明,对于任意 x x x ϵ \epsilon ϵ{0,1,2,…, ∑ i = 1 n i \sum_{i=1}^ni ∑i=1ni},都有 ∑ i = 1 k i \sum_{i=1}^ki ∑i=1ki - r r r= x x x
其中,k ≤ \leq ≤ n , r r r ϵ \epsilon ϵ{0,1,2,…, ∑ i = 1 k i \sum_{i=1}^ki ∑i=1ki}
设 b b b,0 ≤ \leq ≤ b b b 满足 b + 1 b+1 b+1 ≤ \leq ≤ k k k,且 ∑ i = 1 b i \sum_{i=1}^bi ∑i=1bi ≤ \leq ≤ x x x, ∑ i = 1 b + 1 i \sum_{i=1}^{b+1}i ∑i=1b+1i ≥ \geq ≥ x x x
∴ \therefore ∴ ∑ i = 1 b i \sum_{i=1}^{b}i ∑i=1bi ≤ \leq ≤ x x x ≤ \leq ≤ ∑ i = 1 b + 1 i \sum_{i=1}^{b+1}i ∑i=1b+1i
又 ∵ \because ∵ r r r= ∑ i = 1 k i \sum_{i=1}^ki ∑i=1ki- x x x
∴ \therefore ∴ ∑ i = b + 2 k i ≤ \sum_{i=b+2}^ki \leq ∑i=b+2ki≤ r r r ≤ \leq ≤ ∑ i = b + 1 k i \sum_{i=b+1}^ki ∑i=b+1ki
我们可以称
∑
i
=
b
+
2
k
i
\sum_{i=b+2}^ki
∑i=b+2ki为0
又
∵
\because
∵
∑
i
=
b
+
2
k
\sum_{i=b+2}^k
∑i=b+2k
≥
\geq
≥ 0
∑ i = b + 1 k i \sum_{i=b+1}^ki ∑i=b+1ki ≤ \leq ≤ ∑ i = 1 k i \sum_{i=1}^ki ∑i=1ki
∴ \therefore ∴ 0 ≤ \leq ≤ r r r ≤ \leq ≤ ∑ i = 1 k i \sum_{i=1}^ki ∑i=1ki
证毕
有了这个思路,代码就很Easy了
1:无解,只需判断a+b是否是前缀和即可
2:从1~n累加now,当发现now加上i后超过了a或b,就记录下now-a或now-b,除了它,其他的构成一组解
Code:
#include<cstdio>
#include<iostream>
#include<map>
using namespace std;
#define int long long
int n,m,a[100005],t,sum[100005],now,st[100005],op;
map<int,int> mp;
map<int,bool> vis;
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=100000;i++)
{
sum[i]=sum[i-1]+i;
mp[sum[i]]=i;
}
if(!mp[n+m])
{
printf("No");
return 0;
}
int k=mp[n+m],delta=min(n,m);
printf("%lld",k);
for(int i=1;i<=k;i++)
{
now+=i;
vis[i]=1;
if(now>delta)
{
op=now-delta;
vis[op]=0;
break;
}
}
if(m==delta)
{
for(int i=1;i<=k;i++)
{
if(!vis[i])
{
printf(" %lld",i);
}
}
return 0;
}
else{
for(int i=1;i<=k;i++)
{
if(vis[i])
{
printf(" %lld",i);
}
}
return 0;
}
return 0;
}
注:此代码常数有点大,所以应该是(时间)最劣解前后