NOIP2013 提高組複賽解題報告
NOIP2013 提高組複賽
1002. 火柴排隊
- 貪心+資料結構/歸併排序
這個“相鄰交換”讓我聯想到了NOIP2012_day1_task2_game那題的
噁心做法,於是就專注推導相鄰兩個元素交換對解的影響。然後根據以前經驗知道一定有一個序列可以完全不動,而另一個序列只需要以第一列作為標準移動(所以樣例解釋反而給的誤導很大)。於是很快就確信正解了。現在想起來還有一點小激動,自己居然能找出規律來。
首先,一定可以只對某一組的元素進行交換,能以給定的最少步數,得到另外一組的結果。顯然當前序列還缺少k步就和另外一個序列相同時,另外一個序列一定也只需要k步就可以和當前序列相同。
其次,由於只能相鄰交換,對於每一次的操作,它對於解的影響一定只與這一對元素有關。於是我們對相鄰元素的數量關係進行推導:
假設有兩組元素
則說明有
顯然上式滿足的唯一情況就是
我們對於
於是我們想到了氣泡排序和逆序對,隨便求求逆序對的個數就可以了。採用歸併排序完成的方法和資料結構統計的方法都是可以的。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define M 100005
#define P 99999997
using namespace std;
template <class temp>
inline void Rd(temp &res){
res=0;char c;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
}
int n,a[M],b[M],p[M],q[M];
long long cnt=0;
bool cmp(int a1,int a2){return b[a1]<b[a2];}
bool _cmp(int p1,int p2){return a[p1]<a[p2];}
void Merge(int L,int R){
if(L==R)return;
int mid=L+R>>1;
Merge(L,mid),Merge(mid+1,R);
int low=L,high=mid+1,tot=L;
while(low<=mid&&high<=R)
if(b[low]<b[high])p[tot++]=b[low++];
else{
cnt+=mid-low+1;
p[tot++]=b[high++];
}
while(low<=mid)p[tot++]=b[low++];
while(high<=R)p[tot++]=b[high++];
for(int i=L;i<=R;i++)b[i]=p[i];
}
int main(){
Rd(n);
for(int i=1;i<=n;i++)Rd(a[i]),q[i]=i;
for(int i=1;i<=n;i++)Rd(b[i]),p[i]=i;
sort(q+1,q+n+1,_cmp);
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++)b[p[i]]=q[i];
Merge(1,n);
cnt%=P;
printf("%d\n",(int)cnt);
}
1003. 火車運輸
- 並查集+啟發式合併
- 生成樹+LCA
- 離線+整體二分
現在遇到這種走路徑限值的題目就非常害怕。因為標程幾乎與Dijkstra那種圖論演算法根本搭不上邊……寫這種題目的時候應當將每個點作為集合,或者說集合中的元素來看,然後再採用合併集合的思想進行考慮。
根據本題還要總結一個教訓:對於任何圖論題,一定要儘可能將其轉化為樹論題。因為樹的性質和可行操作遠遠比圖要多,處在一個圖為樹的環境下,顯然思路會更加廣闊。
無論如何,這題都是一道大寫的好題。
可能考慮對於每一個詢問,我們都跑一遍單源最短路演算法,並且要求從經過邊權儘可能大的點來轉移。在此基礎上進行少許優化,期望得分只有30分。
之後由於要求路徑上“最小值最大”,於是我們考慮二分的做法。保留所有不小於列舉的最小值的邊,再判斷需要的路徑是否連通即可。複雜度來說,對於
撇開這種做法不談,我們可以參照NOIP2012_day2_task2_classroom的二分轉線性思路,按邊權從大到小列舉這個邊權。於是接下來只需要在不斷合併的過程中,詢問的路徑由於邊的不斷加入而趨向連通。當它第一次連通的時候,加入的邊權值就是這個詢問的答案了。合併操作我們一般採用並查集去完成。如果判定是否詢問的兩點連通採用直接for過來的方法,時間複雜度為
實際上加入了一條邊就是將兩個端點所在的集合進行合併,我們可以在進行合併操作的時候順便處理掉詢問,然後再把沒有處理掉的兩個集合的詢問合併起來。顯然在極端情況下,如果我們把大集合向小集合進行合併,那麼大集合內掛的詢問被訪問的次數就是
顯然我們可以改變這個合併的順序,使得每一個詢問的訪問次數都穩定在