1. 程式人生 > >$[ POI 2017 ] Podzielno$

$[ POI 2017 ] Podzielno$

沒有 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}\)

    ,則有\(B^K\equiv1\pmod{B-1}\),所以位的不同不會影響數字對\(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\)

    即可,註意如果取模答案為\(0\)並不需要減掉個數。

  • 然後構造答案的方法顯然,因為要組成的數字最大,所以大的數字放前面,這樣詢問即可在個數上二分了。

\(\\\)

\(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$