【SPOJ 2319】 BIGSEQ - Sequence (数位DP+高精度)

BIGSEQ - Sequence

 

You are given the sequence of all K-digit binary numbers: 0, 1,..., 2K-1. You need to fully partition the sequence into M chunks. Each chunk must be a consecutive subsequence of the original sequence. Let Si (1 ≤ i ≤ M) be the total number of 1's in all numbers in the ith chunk when written in binary, and let S be the maximum of all Si, i.e. the maximum number of 1's in any chunk. Your goal is to minimize S.

Input

In the first line of input, two numbers, K and M (1 ≤ K ≤ 100, 1 ≤ M ≤ 100, M ≤ 2^K), are given, separated by a single space character.

Output

In one line of the output, write the minimum S that can be obtained by some split. Write it without leading zeros. The result is not guaranteed to fit in a 64-bit integer.

Example

Input:
3 4

Output:
4
 
【题意】
  给定所有 K 位二进制数:0,1,…,2^K-1。你需要将它们分成恰好 M 组,每组都是原序列中连续的一些数。设 Si(1 ≤ i ≤ M)表示第 i 组中所有数的二进制表示中 1 的个数,S 等于所有 Si 中的最大值。你的任务是令 S 最小。

【分析】
  这题竟然1A了超级感动。
  人生第一道重载运算符的高精度。
  主要就是高精度真是好恶心哦..看着别人的代码打的,重载运算符之后就直接用了很方便。
  
   进入正题,最大值最小,我们就想到可以二分S,然后划分区间使得每个区间都小于S。
  问题就变成了有限制S,然后把它划分成最少的区间,判断区间数是否<=m。
  假设我们现在在st的位置,要找最远的ed使得st+1到ed中的数的1的个数<=S。
  设c[i]表示小于等于i的数的1的个数和,上面的限制就是c[ed]-c[st]<=S -> c[ed]<=S+c[st]
  所以变成找最大的ed使
c[ed]<=S+c[st]。
  c数组当然不能每个都求,我们用到他的时候就用数位DP求,具体过程就是模拟填数。
  
找最大的ed使c[ed]<=S+c[st]也是一个模拟填数的过程,也是一个数位DP。
 
  数位DP中用到的数组是d[i],f[i]。
d[i]表示2^i,f[i]表示小于等于d[i]的数中的1的个数和。初始化求出这两个数组。
  
  填数的时候注意1的个数计算。我一开始就傻逼了。
  前面填过的1并没有在答案中减去,判断可不可以走左子树的时候要记得把这个也加上判断。

代码如下:
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<string>
  7 #include<queue>
  8 #include<cmath>
  9 using namespace std;
 10 #define Maxn 110
 11 
 12 struct bign
 13 {
 14     int len,a[Maxn];
 15     bign ()
 16     {
 17         memset(a,0,sizeof(a));
 18         len=1;
 19     }
 20     bign (int num)
 21     {
 22         *this = num;
 23     }
 24     bign operator = (const int num)
 25     {
 26         char s[Maxn];
 27         sprintf(s,"%d",num);
 28         *this = s;
 29         return *this;
 30     }
 31     bign operator = (const char *num)
 32     {
 33         while(num[0]=='0') num++;
 34         len=strlen(num);
 35         for(int i=0;i<len;i++)
 36           a[i]=num[len-i-1]-'0';
 37         return *this;
 38     }
 39     bign operator + (const bign &b)
 40     {
 41         bign c;
 42         c.len=0;
 43         for(int i=0,g=0;g||i<max(len,b.len);i++)
 44         {
 45             int x=g;
 46             if(i<len) x+=a[i];
 47             if(i<b.len) x+=b.a[i];
 48             c.a[c.len++]=x%10;
 49             g=x/10;
 50         }
 51         return c;
 52     }
 53     bign operator += (const bign &b)
 54     {
 55         *this=*this+b;
 56         return *this;
 57     }
 58     void clean()
 59     {
 60         while(len>1 && !a[len-1]) len--;
 61     }
 62     bign operator * (const bign &b)
 63     {
 64         bign c;
 65         c.len=len+b.len;
 66         for(int i=0;i<len;i++)
 67          for(int j=0;j<b.len;j++)
 68             c.a[i+j]+=a[i]*b.a[j];
 69         for(int i=0;i<c.len;i++)
 70         {
 71             c.a[i+1]+=c.a[i]/10;
 72             c.a[i]%=10;
 73         }
 74         c.clean();
 75         return c;
 76     }
 77     bign operator *= (const bign &b)
 78     {
 79         *this=*this * b;
 80         return *this;
 81     }
 82     bign operator - (const bign b)
 83     {
 84         bign c;
 85         c.len=0;
 86         for(int i=0,g=0;i<len;i++)
 87         {
 88             int x=a[i]-g;
 89             if(i<b.len) x-=b.a[i];
 90             if(x>=0) g=0;
 91             else
 92             {
 93                 g=1;
 94                 x+=10;
 95             }
 96             c.a[c.len++]=x;
 97         }
 98         c.clean();
 99         return c;
100     }
101     bign operator -= (const bign &b)
102     {
103         *this = *this -b;
104         return *this;
105     }
106     bign operator / (const int b)
107     {
108         bign c;
109         int f=0;
110         for(int i=len-1;i>=0;i--)
111         {
112             f=f*10+a[i];
113             c.a[i]=f/b;
114             f=f%b;
115         }
116         c.len=len;
117         c.clean();
118         return c;
119     }
120     bign operator / (const bign &b)
121     {
122         bign c,f=0;
123         for(int i=len-1;i>=0;i--)
124         {
125             f=f*10;
126             f.a[0]=a[i];
127             while(f>=b)
128             {
129                 f-=b;
130                 c.a[i]++;
131             }
132         }
133         c.len=len;
134         c.clean();
135         return c;
136     }
137     bign operator /= (const bign &b)
138     {
139         *this = * this /b;
140         return * this;
141     }
142     bign operator % (const bign &b)
143     {
144         bign r= *this /b;
145         r=*this-r*b;
146         return r;
147     }
148     bign operator %= (const bign &b)
149     {
150         *this=*this%b;
151         return *this;
152     }
153     bool operator < (const bign &b)
154     {
155         if(len!=b.len) return len<b.len;
156         for(int i=len-1;i>=0;i--)
157          if(a[i]!=b.a[i]) return a[i]<b.a[i];
158         return false;
159     }
160     bool operator > (const bign &b)
161     {
162         if(len!=b.len) return len>b.len;
163         for(int i=len-1;i>=0;i--)
164          if(a[i]!=b.a[i]) return a[i]>b.a[i];
165         return false;
166     }
167     bool operator == (const bign &b)
168     {
169         return !(*this>b) && !(*this<b);
170     }
171     bool operator != (const bign &b)
172     {
173         return !(*this==b);
174     }
175     bool operator <= (const bign &b)
176     {
177         return (*this<b)||(*this==b);
178     }
179     bool operator >= (const bign &b)
180     {
181         return (*this>b)||(*this==b);
182     }
183 };
184 
185 void output(bign x)
186 {
187     for(int i=x.len-1;i>=0;i--) printf("%c",x.a[i]+'0');
188     printf("\n");
189 }
190 
191 int k,m;
192 bign d[Maxn],f[Maxn];
193 void init()
194 {
195     d[0]=1;
196     for(int i=1;i<=k;i++) d[i]=d[i-1]*2;
197     f[1]=1;
198     for(int i=1;i<=k;i++) f[i]=f[i-1]*2+d[i-1];
199 }
200 
201 bign get_ct(bign x)
202 {
203     bign ans=0;
204     if(x==-1) return 0;
205     int y=0;
206     for(int i=k;i>=1;i--)
207     {
208         bign now=x/d[i-1];
209         if(now==1) ans+=f[i-1]+d[i-1]*y,y++;
210         x%=d[i-1];
211     }
212     return ans+y;
213 }
214 
215 bign get_f(bign x)
216 {
217     bign ans=0;
218     int y=0;
219     for(int i=k;i>=1;i--)
220     {
221         if(d[i-1]*y+f[i-1]<x) ans+=d[i-1],x-=d[i-1]*y+f[i-1],y++;
222     }
223     if(x>=y) return ans; 
224     return ans-1;
225 }
226 
227 bool check(bign x)
228 {
229     bign st=0;
230     int now=0;
231     while(st<d[k]-1)
232     {
233         bign y=get_ct(st),ed=get_f(y+x);
234         now++;
235         if(now>m) return 0;
236         st=ed;
237     }
238     return 1;
239 }
240 
241 void ffind()
242 {
243     bign l=1,r=f[k];
244     while(l<r)
245     {
246         bign mid=(l+r)/2;
247         if(check(mid)) r=mid;
248         else l=mid+1;
249     }
250     output(l);
251 }
252 
253 int main()
254 {
255     scanf("%d%d",&k,&m);
256     init();
257     ffind();
258     return 0;
259 }
[SPOJ 2319]

 

 

打这个真是太不容易了!!!!

 


 

放一个大神的题解,如果看不懂我说的东西的话:

 

 

posted @ 2016-10-11 21:21  konjak魔芋  阅读(351)  评论(0编辑  收藏  举报