两数之和(数学
题目描述
我们知道从
注意有多组数据
我觉得很妙,甚是可以写一篇题解;
我们有
这就有了以下数对和
这就是输入,我们把它们装在数组
展开上式可以得到
这个略丑, 我们稍加整理
这样子我们可以得到一个倒三角形,
且发现每一行,每一列都有一个相同的元素,又由于我们求的
每一行,从左到右,值依次递增
每一列,从上到下,值依次递增
元素周期表的感觉
可以进一步推出当前图最小的那个点一定在左上角(<-突破口
意味着将
那假如我们现在知道
我们在
当前得到了
现在最小的就是
我们发现用这种方法就可以求出所有的元素;
如果还有点不理解的话,可以看看文章底部的模拟;
当然这建立在知道
操作中涉及到 查询最小值,删除值,可以用
又想到
这样子枚举
所以对于一个数据点的时间复杂度的上界是
如何处理
讲的有些复杂,很多内容可以直接跳过;
#include<bits/stdc++.h>
#define mp make_pair
#define ll long long
using namespace std;
int n;
int sum[50];
int a[20];
bool fl;
multiset<int> s;
multiset<int>::iterator it;
inline int read()
{
int x=0,fl=1;char st=getchar();
while(st<'0'||st>'9'){ if(st=='-')fl=-1; st=getchar();}
while(st>='0'&&st<='9') x=x*10+st-'0',st=getchar();
return x*fl;
}
inline bool check(int x)
{
a[1]=x; //确定a[1]
for(int i=2;i<=n;i++)
{
a[i]=*s.begin()-a[1]; //确定a[i]
for(int j=1;j<i;j++)
{
it=s.find(a[j]+a[i]);
if(it==s.end()) //当前的a[1]不成立
return 0;
s.erase(it); //删除倒三角形中第i列下方的点
}
}
return 1;
}
int main()
{
while(~scanf("%d",&n))
{
fl=0; // 记得初始
for(int i=1;i<=n*(n-1)/2;i++)
sum[i]=read();
sort(sum+1,sum+1+n*(n-1)/2);
for(int i=0;i<=(sum[1]/2);i++)
{
s.clear();
for(int j=1;j<=n*(n-1)/2;j++)
s.insert(sum[j]); //初始multiset
if(check(i)) //有一组解就输出
{
for(int j=1;j<=n;j++)
printf("%d ",a[j]);
puts("");
fl=1;
break;
}
}
if(!fl)printf("Impossible\n"); //无解
}
return 0;
}
这里模拟一下