給乙個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開始加到...