題解:二分答案。
這道題貌似是某年ioi的弱化版。
有乙個非常厲害也非常好用的結論:對於遊戲的乙個形如「ababababa.."的操作序列,在所有a操作不變得前提下,可以找到乙個形如」aaaaabbbbb"的操作序列,使兩個序列作用於同乙個排列的效果相同。
有了這個結論的基礎這個題就好做多了。問題就轉化成了最少需要幾次操作將序列變成公升序(可以交換不相鄰的,如果只能交換相鄰的就變成了樹狀陣列求逆序對)
這個需要怎麼搞呢?我們可以從前向後掃,如果當前位置的數不是應該在這個位置的數,就找到應該在這個位置的數,然後將其交換,最終交換了幾次最少的操作次數就是幾。
但是還有別的方法:
以5 4 3 2 1 為例
我們可以發現5,1雖然不在自己應該在的位置,但是如果把它們兩個看成整體,對於整個序列來說它們佔據了排好序後5,1應該在的位置,所以對於整個序列來說是有序的,它們只是自身內部無序而已。5應該到1處,1應該到5處,形成了乙個迴圈,所以可以將它們抽象成乙個環,環內換序就可以了。(下面把這種環稱為迴圈節)
對於乙個含有n個元素的迴圈節來說,要使其有序,要交換n-1次(前面都排好了,最後乙個數自然有序就不用排了)。
上例中3在原本就在的位置,可以看成乙個元素的迴圈節。
我們可以推斷出有乙個迴圈節,就可以少交換一次,因為n個元素的迴圈節,只需交換n-1次即可有序。
那麼對於整個序列來說,最少交換次數為 元素總數-迴圈節個數。那麼例子中的答案就是2.
然後這道題其實就只需要二分答案然後判定了。
#include#include#include#include#include#define n 600003
using namespace std;
int x[n],y[n],a[n],b[n],pos[n],n,m;
bool pd(int num)
if (t<=num) return true;
return false;
}int main()
printf("%d\n",ans);
}
#include#include#include#include#include#includeusing namespace std;
const int n=610000;
int n,m,i,a[n],s[n],x[n],y[n],vis[n];
int check()
{ int ret=0;
memset(vis,0,sizeof(vis));
for (int i=0;i>1;
for (i=0;i
二分查詢與二分答案
主要用於在乙個單調的函式中查詢某值 連續函式的情況 若當前查詢的區間是 l,r 查詢的值是 y 函式單增 設 mid l r 2 若 f mid y 則 l mid,否則 r mid 直至 r l eps 當前查詢的區間是 l,r 查詢的值是 y 函式單增 設 mid l r 2 若 f mid y...
二分查詢和二分答案
1.解釋 優點 查詢速度快。缺點 待查表為有序表。4.時間複雜度 o log n 5.示例 p2249查詢 include include using namespace std long long n,m,a 1000005 b 100005 l,r,mid,cnt,x intmain for i...
二分與二分答案學習
判斷left,mid,right的符號進行區間的精確。如下為遞迴二分求零點的操作 double find zero point double left,double right,double precesion double mid right left 2 if f mid 0 if f mid ...