[NOIP2006]2^k进制数

做题时间:2021.02.03

\(【题目描述】\)

问有多少个\(2^k(k \leq 9)\)进制数满足:

  1. 至少有\(2\)位;
  2. 转化为\(2\)进制数之后最多有\(w\)位。
  3. 除最后一位外,每一位都严格小于右边一位

\(【输入样例】\)

3 7

\(【输出样例】\)

36

\(【考点】\)

动态规划 or 组合数学、高精度

\(【做法】\)


\(【代码】\)

#include<cstdio>
#include<iomanip>
#include<iostream>
#include<cstring>
using namespace std;
const int N=205;
const int M=1<<9;
string C[M][M],p,t,ans;
int a[N],b[N],c[N];
int w,k;
inline int Swap(int &x,int &y){int t=x;x=y;y=t;}

string Add(string sa,string sb)//高精度加法 
{
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(b,0,sizeof(c));
	t="";
	int lena=sa.size();
	int lenb=sb.size(),lenc;
	for(int i=0;i<lena;i++) a[i+1]=sa[lena-i-1]-'0';
	for(int i=0;i<lenb;i++) b[i+1]=sb[lenb-i-1]-'0';
	int i=1,x=0;
	while(i<=lena||i<=lenb){
		c[i]=a[i]+b[i]+x;
		x=c[i]/10;
		c[i]%=10;
		i++;
	}
	
	if(x) c[i]=x;
	else i--;
	lenc=i;
	for(int i=lenc;i>=1;i--) t+=(char)c[i]+'0';
	return t;
}
int main()
{
	scanf("%d%d",&k,&w);
	int ed=1<<k,sp=1<<w%k;
	
	C[0][0]="1";
	for(int i=1;i<=ed;i++) C[i][0]=C[i][i]="1";
	for(int i=2;i<=ed;i++){
		for(int j=1;j<i;j++) C[i][j]=Add(C[i-1][j],C[i-1][j-1]);//预处理组合数 
	}
	
	//这里其实可以将k整除w和k不整除w两种情况写在一起 
	for(int i=2;i<=w/k;i++){
		if(i>ed-1) break;
		ans=Add(ans,C[ed-1][i]);//累加 
	}
	for(int i=1;i<=sp-1;i++){
		if(w/k>ed-i-1) break;
		ans=Add(ans,C[ed-i-1][w/k]);//累加 
	}
	int len=ans.size();
	for(int i=0;i<len;i++) printf("%c",ans[i]);
	return 0;
}

posted @ 2021-02-03 17:13  lxzy  阅读(125)  评论(0)    收藏  举报