無進製加法

2022-06-03 09:24:15 字數 3907 閱讀 5226

先考慮乙個多項式做法:

根據套路從高到低位確定答案。

令當前位\(i\)為\(0\),貪心的讓後面合法。顯然把\(1~i-1\)位都設成\(1\)進行判定。

考慮當前\(a\)的最大值\(v\),掃到第\(j\)位。

如果\(v\)的長度大於\(j\)顯然無解

否則如果\(v\)的第\(i\)位為\(0\),則刪除最大值繼續判定。

如果\(v\)的第\(i\)為為\(1\),則把這一位的\(1\)和前導\(0\)刪除後繼續判定

取出最大值的正確性可以感性理解,就是如果當前位不覆蓋最大值,則後面的位更難覆蓋。

考慮加速比較的過程。

我們需要支援乙個資料結構,要求快速插入,刪除最大值,取出最大值。

使用堆+二分+雜湊可以做到\(o(n^2\log_2^2n)\)

但是我們比較只涉及兩個開頭為\(1\)的某個字串的字尾(還要把前面補\(0\))比較。

使用基數排序/二分+雜湊即可將所有字尾排序。

比較時間複雜度降低至\(o(n^2\log_2n)\)

70分**如下:

#includeusing namespace std;

#define n 500010

#define int long long

#define m1 998244353

#define m2 1000000007

int n,l[n],ct,p1[n],p2[n],h1[n],h2[n],cc,ans[n],cv,la[n],rk[n],st[n],lv[n],dl[n],tp[n];

char c[n],ch[n*30];

vectorv[n],id[n];

struct no;

struct nnp[n];

int operator <(no x,no y));

cv++;

}for(int j=i-1;j;j--)

else if(x.le==j)

else

ct++;

}else

ct++;

}if(ct!=cv)

ok=0;

if(ok)

ans[i]=0;

else);

no x=q.top();

q.pop();

if(x.le==i)

else

dl[x.x]=1;

ans[i]=1;

}} int ok=0;

for(int i=ml+n+1;i;i--)

}}

想要獲得正解,需要發現更多性質。

有部分分\(a_i=2^k\)。這個部分分的特點:在上面演算法,討論\(a_i\)是否等於\(0\)是不必要的。因為如果覆蓋當前位置,當前位置的元素就會被刪除。

還是考慮判定當前位是否能為1。把所有數按照\(k\)從大到小排序。

令\(mx_i=l_i+i-1\)的最大值,其中\(l_i\)為第\(i\)位的長度。則只要判定當前位\(mx\)是否小於\(x\),即可判定

這是因為如果我們用乙個全是\(1\)的字首貪心覆蓋當前點,則到當前點\(j\)的串長度為\(i-j\)。

推一下就知道這樣子是正確的。

維護乙個指標\(pt\)表示判定到**。如果當前位置放置\(1\),則\(pt--\)否則不變。

使用\(mx_pt\)即可判定當前位置是否一定要放\(1\)。

一般情況也是把所有有用的字尾(開頭為\(1\))從大到小排。

在一般情況,令\(mx=l_i+i-1\)的最大值,則答案長度的上界是\(2^\),下界是\(2^\),把所有數變為\(2^\)和\(2^\)就可以證明。

考慮我們的貪心過程。如果我們當前的\(mx<\)的話,則前面的位都會被刪除。

當前位由於我們放置的\(1\)等於當前位的最大值的最高位,所以把當前位刪除首位的\(1\),前面位全部刪除即可繼續判定。

可以遞迴。

設\(pd(b)\)表示答案長度最大為\(b\)是否合法

我們判定答案長度是否能是\(2^\),把當前位\(k\)刪除首位的\(1\),前面位全部刪除即可遞迴\(pd(b-k)\)。

可以把當前位刪除,當前位的後面乙個字尾插入。

判定答案長度是否能是\(2^\),把當前位\(k\)和前面位全部刪除即可遞迴\(pd(b-k+1)\)

使用乙個下標為所有字尾排名的線段樹維護\(l_i+i-1\),如果刪除就是把當前位置置為\(-\inf\),當前位置後面的數\(-1\)。

插入就是如果刪除就是把當前位置加上\(-\inf\),當前位置後面的數\(+1\)。

用線段樹二分找到第乙個\(=mx\)的位置。

如果當前位置可以更新答案,則前面沒卡到上界的位都是取到\(10000...0000\)。

時間複雜度不會證明,但是好像是\(o(|s|\log_2|s|)\)

**非常長,但是是因為內嵌暴力導致的。

#includeusing namespace std;

#define n 300010

int n,l[n],ct,ans[n],cv,la[n],rk[n],st[n],lv[n],dl[n],tp[n],h1[n],rr[n],cs,ss[n],tt,nx[n];

char c[n],ch[n];

vectorid[n],lg[n],vi[n];

struct nna[n];

struct nt;

int operator <(nn x,nn y)

} void ad(int o,int l,int r,int x,int y,int z)

pd(o);

int md=(l+r)/2;

qp(o*2,l,md,vc);

if(mx[o*2]ml)

return 0;

vectorva;

t.qp(1,1,cv,va);

int po=va.back();

va.pop_back();

for(int i=0;i=b-sz;i--)

ans[i]=1;

return 1;

} if(la[ss[po]])

dd(rk[la[ss[po]]]);

if(b+1<=ml&&dfs(b-(int)va.size()))

for(int i=0;i=i)

break;

s.erase(s.begin());

} int ct=0;

for(it=s.begin();it!=s.end();it++);

} sort(a+1,a+ct+1);

for(int j=1;j<=ct;j++)

rk[a[j].i]=++cg;

} if(sl<=1000));

cv++;

}for(int j=i-1;j;j--)

else if(x.le==j)

else

ct++;

}else

ct++;

}if(ct!=cv)

ok=0;

if(ok)

ans[i]=0;

else);

no x=q.top();

q.pop();

if(x.le==i)

else

dl[x.x]=1;

ans[i]=1;

}} int ok=0;

for(int i=ml+n+1;i;i--)

} else

for(int i=1;i<=n;i++)

for(int j=0;jif(j&&!(vi[i][j]&&!nx[id[i][j]]))

dd(rk[id[i][j]]);

dfs(1e9);

int ok=0;

for(int i=ml+n+1;i;i--)

}}

loj2850 無進製加法

似乎漏了乙個資料範圍,cf上的題面中還有 sum l le 3 cdot 10 考慮 a 2 時 不妨 k ge k ge ge k 記 sum b 的最高位為 l 則有 l max k i 1 證明 大於等於 2 的 b 至少要 i 個,因此該值即為下限 取 b 2 i 1 ge 2 因此一定可行...

ROI 2018 Day 2 無進製加法

題目大意 給出二進位制數 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,貪心確...

XDOJ B進製加法

時間限制 1 sec 記憶體限制 128 mb 提交 301 解決 62 提交 狀態 討論版 小w在iphone上裝了乙個計算器程式,可以處理b進製數。亮亮對此非常鄙視,說 我口算都能把b進製數的加減乘除算出來!現有有兩個b進製正整數x y,亮亮算出了它們的和 也用b進製表示 你需要寫乙個對拍程式。...