$[ POI 2017 ] Podzielno$
阿新 • • 發佈:2018-09-08
沒有 cstring 什麽 pmo struct 取模 tchar 得到 二分
\(\\\)
\(Description\)
\(B\)進制數,每個數字\(i(i\in [0,B-1])\)有\(A_i\)個。用這些數字組成一個最大的\(B\)進制數\(X\)(不能有前導零,不需要
用完所有數字),使得\(X\)是\(B-1\)的倍數。\(q\)次詢問,每次詢問\(X\)在\(B\)進制下的第\(k\)位數字是什麽。
- \(B\in [2,10^6]\),\(A_i\in [1,10^6]\),\(q\in [1,10^5]\),\(k\in [1,10^{18}]\)
\(\\\)
\(Solution\)
首先考慮位本身的影響,因為\(B\equiv1\pmod{B-1}\)
於是把每一位拆開看,假設一共有\(len\)個數位,第\(i\)位放的數為\(d_i\),則該數在\(B-1\)的剩余系下的答案為\(\begin{align}\sum_{i=0}^{len-1}d_i\times B^i\equiv \sum_{i=0}^{len-1}d_i\pmod{B-1}\end{align}\)
於是直接將給出的數字求和,並對\(B-1\)取模,註意到數據有一個很好的性質,所有的數字至少有一個,所以直接將求和取模得到的數個數\(-1\)
然後構造答案的方法顯然,因為要組成的數字最大,所以大的數字放前面,這樣詢問即可在個數上二分了。
\(\\\)
\(Code\)
#include<cmath> #include<cstdio> #include<cctype> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 100010 #define R register #define gc getchar using namespace std; int f[N]; struct lim{int l,r;}s[N]; struct seg{int l,r,val;}p[N]; inline int rd(){ int x=0; bool f=0; char c=gc(); while(!isdigit(c)){if(c=='-')f=1;c=gc();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();} return f?-x:x; } inline bool cmp1(lim x,lim y){return x.l==y.l?x.r<y.r:x.l<y.l;} inline bool cmp2(seg x,seg y){return x.r==y.r?x.l<y.l:x.r<y.r;} inline int find(int x){ int l=0,r=x-1; while(l<r){ int mid=((l+r+1)>>1); if(p[mid].r<p[x].l) l=mid; else r=mid-1; } return l; } int main(){ int n=rd(),tot1=0,tot2=0; for(R int i=1,l,r;i<=n;++i){ l=rd(); r=rd(); if(l+r<n){s[++tot1].l=l+1;s[tot1].r=n-r;} } sort(s+1,s+1+tot1,cmp1); for(R int i=1,cnt;i<=tot1;++i){ cnt=1; while(s[i+1].l==s[i].l&&s[i+1].r==s[i].r) ++cnt,++i; cnt=min(cnt,s[i].r-s[i].l+1); p[++tot2].l=s[i].l; p[tot2].r=s[i].r; p[tot2].val=cnt; } sort(p+1,p+1+tot2,cmp2); for(R int i=1;i<=tot2;++i) f[i]=max(f[i-1],f[find(i)]+p[i].val); printf("%d\n",n-f[tot2]);
$[\ POI\ 2017\ ]\ Podzielno$