一本通1649【例 2】2^k 进制数
1649:【例 2】2^k 进制数
时间限制: 1000 ms 内存限制: 524288 KB
【题目描述】
原题来自:NOIP 2006 提高组
设 r 是个 2k 进制数,并满足以下条件:
1、r 至少是个 2 位的 2k 进制数。
2、作为 2k 进制数,除最后一位外,r 的每一位严格小于它右边相邻的那一位。
3、将 r 转换为 2 进制数 q 后,q 的总位数不超过 w。
在这里,正整数 k 和 w 是事先给定的。
问:满足上述条件的不同的 r 共多少个?
【输入】
输入只一行,为两个正整数 k 和 w。
【输出】
输出为一行,是一个正整数,为所求的计算结果,即满足条件的不同的 rr 的个数(用十进制数表示,要求最高位不得为 0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。
提示:作为结果的正整数可能很大,但不会超过 200 位。
【输入样例】
3 7
【输出样例】
36
【提示】
数据范围与提示:
对于所有数据,1≤k≤9,k<w≤3×104 。
sol:这道其实是道大水题
对于条件二很容易发现是个组合数,而且是严格小于,k的范围也不大,直接n2预处理组合数
统计答案是注意讨论首位是0和非0的情况
Ps:裸的高精貌似会MLE,建议压位
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int Base=10000,power=4; int K,B,W; struct Bignum { int a[105]; Bignum(){memset(a,0,sizeof a);} Bignum(int x) { memset(a,0,sizeof a); while(x) { a[++a[0]]=x%Base; x/=Base; } return; } inline void print() { int i; write(a[a[0]]); for(i=a[0]-1;i>=1;i--) { if(a[i]<1000) putchar('0'); if(a[i]<100) putchar('0'); if(a[i]<10) putchar('0'); write(a[i]); } return; } }C[515][515],ans; #define P(x) x.print(),putchar(' ') #define Pl(x) x.print(),putchar('\n') inline Bignum operator+(const Bignum &p,const Bignum &q) { int i; Bignum ans=p; for(i=1;i<=q.a[0];i++) { ans.a[i]+=q.a[i]; ans.a[i+1]+=ans.a[i]/Base; ans.a[i]-=(ans.a[i]>=Base)?Base:0; } while(ans.a[ans.a[0]+1]) ans.a[0]++; return ans; } int main() { int i,j; R(K); R(W); B=1<<K; C[0][0]=Bignum(1); for(i=1;i<=B;i++) { for(j=0;j<=B;j++) { C[i][j]=C[i][j]+C[i-1][j]; if(j) C[i][j]=C[i][j]+C[i-1][j-1]; } } int oo=W%K,Up=W/K; for(i=min(Up,B-1);i>=2;i--) { ans=ans+C[B-1][i]; } if(oo) { int Last=(1<<oo)-1; for(i=1;i<=Last;i++) if((B-i-1)>=Up) { ans=ans+C[B-i-1][Up]; } Pl(ans); } else { Pl(ans); } return 0; } /* input 3 7 output 36 input 2 8 output 4 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!