题目大意
有个数列a[i],让其重新排列使得a[i]*a[i+1] (i=1~n-1)求和最大,之后输出重新排列后的编号,要求字典序最小。
正解
这个题是真的烦人,代码也很繁琐,就粗略看看吧。然后具体是贪心做法,假如没有重复的,那么显然是头放最小,尾放次小,头再放此次小,这样。(注意考虑字典序,也就是考虑是头放最小还是次小)之后假如有重复的,就自行讨论一下。
- 如果这个数出现的次数>=2,那么这个数必定会放入待解决数列头和待解决数列尾。
而取决于放多少个进待解决数列头,取决于,他后面的前两个数的最前位置及出现
次数。 - 如果这个数出现的次数=1
a) 如果 i 位置元素的值小于 j 位置元素的值,显然会放到 i 的右方。
b) 大于的话,显然会放到 i 的左方。
c) 等于的话
i. 如果后一个数的最小位置小于现在的数的位置,则放在 j 的左方。
ii. 反之,放在 i 的右方。
讨论的也许与读者的思路有所不同,希望读者自己仔细推一遍。
然后扯一下是先要排序啊,按权值再按编号。
(照抄题解,是真的烦人啊这道题)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define N 100007
using namespace std;
int t,n,b[N],ans[N];
struct node{
int x,w;
}a[N];
bool cmp(node a,node b){
if(a.x==b.x) return a.w<b.w;
return a.x<b.x;
}
int find(int x){
while(x<n&&a[x+1].x==a[x].x) x++;
return x;
}
int main(){
freopen("permutation.in","r",stdin);
freopen("permutation.out","w",stdout);
scanf("%d",&t);
while(t--){
memset(a,0,sizeof