1. 程式人生 > 實用技巧 >一個傻逼題

一個傻逼題

題目連線

體驗++

我們首先從確定演算法著手

$ n=1e6 $

根據常識,我們可以選擇的有\(O(nlogn) or O(n)\)

同樣根據常識\(O(nlogn)的玩意兒有二分,線段樹等等\)

\(O(n)\)的玩意兒有dp,貪心

\(dp\)我覺得起碼要開二維才行,否則弄不出來的

那麼就只剩下貪心和二分線段樹之類的

首先二分線段樹之類我是實在想不出怎麼做

貪心倒是可以做出來

思路

XBB結束

我們讓他們第一次過去全部出隊

回來的一趟再把他們拉回來再出隊(霧

我們想想

比如一組數

1 2 3 4 5 6

把第i位拉出來放在最後

是不是隻對\(i+1->n\)的排名有影響?

那麼我們就更新...等等!這不就成\(O(n^2)\)

了嗎?

我們需要用聰明的方法來玄學優化這一個更新

明顯,\(i+1->n\)排名均\(--\)

那麼我們用結合律搞一下,不就是減去\(\sum_{j=i+1}^n a(j)嗎\)

那麼加一個字首和優化一波

然後我們再用指標亂搞一下排名

就AC啦~

#include<bits/stdc++.h> 
#define N 1001001
#define int unsigned long long
using namespace std;
inline int read( ){
	int sum=0,ft=1;
	char ch=getchar( );
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar( );
	if(ch=='-'){
		ch=getchar( );
		ft=-1;
	}
	while(ch>='0'&&ch<='9'){
		sum=ch-'0'+(sum<<3)+(sum<<1);
		ch=getchar( );
	}
	return ft*sum;
}
inline void print(int k){
	if(!k)return;
	print(k/10);
	putchar(k%10+'0');
}
int sum[N],n,a[N],pre[N],nex[N],last,xu[N];
inline void work(int k){
	nex[last]=k;
	pre[nex[k]]=pre[k];
	nex[pre[k]]=nex[k];
	nex[k]=0;
	pre[k]=last;
	last=k;
}
signed main( ){
	n=read( );
	int i,j,ans=0,k;
	for(i=1;i<=n;i++){
		nex[i]=i+1;
		pre[i]=i-1;
		k=read( );
		sum[i]=k;
		a[i]=k;
		ans=ans+k*i;
	}
	last=n;
	nex[n]=0;
	for(i=n-1;i>=1;i--)sum[i]+=sum[i+1];
	for(i=n;i>=1;i--)
	if((n-i)*a[i]>sum[i+1]){
		ans+=(n-i)*a[i]-sum[i+1];
		work(i);
	}
	print(ans);
	putchar('\n');
	int ci=0,t;
	for(i=1;i<=n;i++)
	if(!pre[i]){
		t=i;
		break;
	}
	while(t){
		xu[++ci]=t;
		t=nex[t];
	}
	for(i=1;i<=n;i++){
		if(a[xu[i]])print(a[xu[i]]);
		else putchar('0');
		putchar(' ');
	}
}