【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 }
打这个真是太不容易了!!!!
放一个大神的题解,如果看不懂我说的东西的话: