题意:给出m个不同的数,并且每个数都有个费用,现在要在m个数中选择一些数,用这些数组成一个长度为n的数列,并且满足任意两个不同种类的数都相邻。问最大的费用是多少。
思路:不同种数的区别只有费用,不妨按费用从大到小排序,现在就是要在前几个数中选一些满足要求。可以把它想象成一个图,每个数代表一个顶点,两个数相邻代表两个顶点之间有条边,根据题中的要求,构造出来的图就是完全图。做题的时候没想那么多,找了找规律A掉了,AC后看题解才发现这题其实很巧妙。这个数列可以看成一个路径,每在当前数列后加一个数就相当于连了一条边,这样这题就变成了找一条欧拉路径!顶点为奇数的时候一定存在欧拉路径,因为每个顶点的度数都为偶数,顶点为偶数的时候要添加一些边来满足要求,添加的边数即为n/2-1。有趣的题~
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=10000+10;
const int Maxn=100000+10;
ll a[maxn];
int w[Maxn];
bool cmp(int x,int y) { return x>y;}
void Init()
{
for(ll i=1;i<maxn;++i)
{
if(i&1) a[i]=i*(i-1)/2+1;
else a[i]=i*i/2;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,tmp;
Init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
scanf("%d%d",&tmp,&w[i]);
sort(w+1,w+m+1,cmp);
int p=0;
for(int i=1;i<maxn;++i)
if(a[i]<=n) p=i;
else break;
ll ans=0;
for(int i=1;i<=min(m,p);++i)
ans+=w[i];
printf("%I64d\n",ans);
return 0;
}