題目大意:
給出二進位制數\(a_1,\ldots a_n\),對於\(b_1\ldots b_n\)
滿足\(a_i\leq b_i\),\(\bigoplus b_i=\sum b_i\),其中$\bigoplus $為異或和
求\(\sum b_i\)最小值
設長度量級為\(n=\sum len(a_i)\)
列舉當前位為0,下面的位為1,貪心確定是否存在方案
檢查乙個答案是否合法:
動態維護乙個倒序的\(a_i\)集合,從高到低考慮每乙個位置
1.如果當前位為0:
如果\(a_i\)中存在大於等於這一位的數,非法
2.如果當前位為1:
2-1.如果\(a_i\)中存在2個當前位為1的數,非法
2-2.如果\(a_i\)中存在恰好乙個,則將這個1用於這個\(a_i\),並將\(a_i\)去掉最高位後放回集合
2-3.不存在,用這個\(1\)刪除最大的乙個\(a_i\)
實際看來,這個貪心本身效率並不高
\[\
\]令\(b=\max\\)
則\(len(ans)\in[b,b+1]\)
上下界均可以由上面的貪心模擬得到
\[\
\]顯然在不斷更改的過程中,當前的\(a_i\)一定是原先的某乙個\(a_i\)的一段字尾
考慮將所有這樣的字尾排序,為了方便,用每乙個最高的1來表示乙個合法的字尾
顯然可以先按照字尾長度分類,同長度的字尾,按照字尾中下乙個1出現的位置排序
也就是乙個類似基數排序個過程,額外維護每乙個字尾中下乙個出現的\(1\)所對應的字尾即可
預處理複雜度為\(o(n\log n)\)
同時,也可以用線段樹快速維護插入/刪除的排名,得到\(b\)的值,單次操作複雜度\(o(\log n)\)
\[\
\]稱滿足\(len(a_i)+i-1=b\)的\(i\)為\(\text\)
令\(p\)為最小的\(\text\),也就是在貪心過程中第乙個出現情況2-1./2-2.的位置
決策答案為\(b\)還是為\(b+1\),也就是決策
是用\(len(a_p)\)這個位置刪除\(a_p\)的最高位,還是用\(len(a_p)+1\)的位置刪除\(a_p\)
(\([1,p-1]\)的部分一定會被刪掉)
\(\text\)採用暴力遞迴來完成確定每一位的這個操作
function solve(limit) limit為當前可以使用的最高位的1
求得 b,p
刪除 a[1,p-1]
刪除 a[p]最高位
if b<=limit and solve(p-1) then
ans[len(a[p]),b]=1
return true
刪除a[p]
if b+1<=limit and solve(p) then
ans[len(a[p])+1,b+1]=1
return true
else return false
end
至於複雜度,官方題解給出為\(o(n)\)次遞迴和刪除/加入操作,最終複雜度為\(o(n\log n)\)
#includeusing namespace std;
#define pb push_back
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template inline void cmin(t &a,const t &b)
template inline void cmax(t &a,const t &b)
void upd(int p,int l,int r,int ql,int qr,int x)
down(p);
int mid=(l+r)>>1;
if(ql<=mid) upd(p<<1,l,mid,ql,qr,x);
if(qr>mid) upd(p<<1|1,mid+1,r,ql,qr,x);
s[p]=max(s[p<<1],s[p<<1|1]);
} void build(int p,int l,int r)
void add(int x,int k)
// find the first critical position "p", and return all the bits in [1,p]
void get(int p,int l,int r,int x,v &r)
} t;
int solve(int l)
// try ans b+1 , so we use bit [nxt+1,b+1] to delete the [1,p]
if(nxt[p]) t.add(nxt[p],-1);
if(bfor(int i:r) t.add(i,1);
return 0;
}int main()
} rk[0]=1e9;
int k=m;
rep(i,0,l-1) );
for(int j:a[i]) id[rk[j]=++k]=j;
k-=a[i].size();
} t.build(1,1,m);
rep(i,1,n) t.add(fir[i],1);
memset(s,0,sizeof s);
drep(i,solve(inf)-1,0) putchar(s[i]^48);
}
NOIP2018 Day2毒瘤題目
拿到題目,一看,圖論,完了.仔細看了看題目,誒這個不是dfs序麼?當場敲出dfs。跑樣例一,過了,結果一跑樣例二,當場廢掉。樣例二有環,會跑不出正解 不知道我的dfs能不能過樹形圖 又手造資料卡死自己的日常 涼掉了.後面仔細想想 好像可以跑乙個最小生成樹?於是開心的打了乙個 color 看起來沒問題...
HEOI 2018 Day2 T2 林克卡特樹
給乙個n個節點的樹,然後將其分成k 1個聯通塊,再在每個聯通塊取一條路徑,將其連線起來,求連線起來的路徑最大權值。考場只會20分,還都打掛了 60分的做法其實並不難,nk dp即可,設 f i,j,0 1 2 表示i子樹選取了j個聯通塊,i這個節點連了0 1 2條邊時的最優解。100分的做法就是60...
NOIP2018 Day2 T1 旅行 題解
乍一看,一道基環樹。說實話考場上有點懵,day2t1直接上基環樹?再一看,好像只是一道無腦的搜尋加剪枝 對於noip資料範圍,o n 2 是可以可過去的 但是對於那個加強版資料,可能需要乙個筆者不會的超級玄學。好吧不扯了,咱們來看看資料範圍。m n 1的情況比較簡單只需一遍跑一邊搜尋,每次找字典序最...