inv 牛客網多校

2021-08-22 04:41:16 字數 1638 閱讀 5290

給乙個1 3 ... n-1的a序列 和乙個2 4 ... n的排列的b序列 問歸併後最小逆序對數 肯定考慮用a** 因為a是有序的(無腦解釋)

首先有個結論 a序列插入時 a[i+1]插入的最優位置一定在a[i]的右邊

//(1,i)|(b[j]>a[i]) 代表[1,n]內有多少b[j]大於a[i]

對於每個a[i] 找乙個p使(1,i)|(b[p]>a[i])+(i+1,n)|(b[p]a[i])-(1,i)|(b[p]a[i])-(1,i)|(b[j]當i==1是 顯然f[i][1]是最小的 當i>1時我們需要根據f[i-1][1] ... f[i-1][n]來得出f[i][1] ... f[i][n]

假設a[i]=2*i-1 a[i+1]=2*i+1 且b序列中2*i這個數的位置在v

(1) 對於j>=v 之前在i-1時 a[i-1]=2*i-1b[v]=2*i 也就是b[v]由(1,i)|(b[j]>a[i])-(1,i)|(b[j](2) 對於i這樣每次對乙個字尾[v,n]減二 最後取個min即可

最巧的地方在於a是全奇 b是全偶 列舉a時每次只增加2 只用考慮夾在a[i-1]與a[i]之間的那個b值即可

至於為什麼會有 a序列插入時 a[i+1]插入的最優位置一定在a[i]的右邊 我的理解是因為每次對乙個字尾減二 所以每次更新後的f[i]是遞減的 所以最優解肯定出現在右邊(強行解釋)

#include using namespace std;

#define ll long long

struct node

;node tree[400010];

int ary[100010],pos[100010];

int n;

void buildi(int l,int r,int cur)

ll queryi(int pl,int pr,int cur)

res=0;

if(pl<=tree[2*cur].r) res+=queryi(pl,pr,2*cur);

if(pr>=tree[2*cur+1].l) res+=queryi(pl,pr,2*cur+1);

return res;

}void updatei(int tar,int cur)

void pushup(int cur)

void pushdown(int cur)

}void buildii(int l,int r,int cur)

void updateii(int pl,int pr,int cur)

pushdown(cur);

if(pl<=tree[2*cur].r) updateii(pl,pr,2*cur);

if(pr>=tree[2*cur+1].l) updateii(pl,pr,2*cur+1);

pushup(cur);

}int main()

buildi(1,n/2,1);

ans=0;

for(i=1;i<=n/2;i++)

//printf("***%lld***\n",ans);

buildii(0,n/2,1);

for(i=1;i<=n/2;i++)

printf("%lld\n",ans);

return 0;

}

Hash Function 牛客網多校

這題竟然卡memset.一開始t了以為陣列開小了 就往大了搞.首先是判矛盾 如果i位置上的乙個數ary i 本來應該在ary i n j處 那j到i之間肯定不能有負數 字首和判斷一下 如果暫時沒矛盾 那就將從j到i 1的位置都向i連一條邊 因為ary i 這個數會出現在i這個位置就是因為j到i 1都...

Prefix Sum 牛客網多校

分塊法真的奇妙 更新操作夠2000次就n k的統一更新一次 期間所有更新存起來 有查詢了先把之前已經更新好的陣列裡的內容取出來 然後把存起來還沒更新的操作算一遍即可 正解線段樹或樹狀陣列 線段樹迷之t include using namespace std define ll long long c...

牛客網多校5 A gpa

輸入 第一行n,k 第二行n個s i 第三行n個c i 最多剪掉k個數使 答案用二分找,做題時想到過,但沒有仔細去想。假設max已知 s i c i s i c i max s i s i 即 s i c i ma x s i c i max 0,只需要每次按 c i max 排序,從k 1開始加到...