2^k进制数

传送
题解大佬的思路令本蒟蒻抖抖发瑟
就由本蒟蒻来讲一讲一个朴素的思路好了
通过题目解释样例可以看出来不管\(r\)的位数是多少,当前的\(r\)对答案的贡献可以用\(sum\)数组维护
为了方便,我们分成两部分来讨论
\(\lfloor \frac{w}{k} \rfloor\)位可填的数范围是完整的\([1,2^k-1]\)(暂时不管填出来是否合法),剩余的1位的填数范围是\([1,2^{w\%k}-1\)
对于这\(\lfloor \frac{w}{k} \rfloor\) 位来说,设\(sum[i][j]\)表示从右往左数\(i\)位,这一位当前填了\(\geq j\)的数,并且合法,对答案的贡献,当\(r\)的位数为\(i\)时,对答案的贡献就是\(sum[i][1]\)
\(sum[i][j]=\Sigma sum[i-1][l],j<l<2^k-1\)
为了省空间,可以开滚动数组

	for(int i=er-1;i>=1;i--) sum[1][i]=sum[1][i+1]+1;
	int n=w/k,nw,sd=er-n;
	for(int i=2;i<=n&&er-i>0;i++)//确保当前枚举的位数有至少一组合法的填法
	{
		int b=i%2;nw=b;
		sum[b][er-i]=sum[b^1][er-i+1];
		for(int j=er-i-1;j>=1;j--) sum[b][j]=sum[b][j+1]+sum[b^1][j+1];
		ans=ans+sum[b][1];
	}

然后再来个高精就可以了
完整代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
	char ch=getchar();
	int x=0;bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
int k,w;
struct gj
{
	int a[209],len;
}sum[2][519],ans;
gj operator +(gj a,gj qaq)
{
	gj rtn;
	int mx=max(qaq.len,a.len),x=0;
	if(a.len<mx) for(int i=a.len+1;i<=mx;i++) a.a[i]=0;
	if(qaq.len<mx) for(int i=qaq.len+1;i<=mx;i++) qaq.a[i]=0;
	rtn.len=mx;
	for(int i=1;i<=mx;i++)
	{
		rtn.a[i]=qaq.a[i]+a.a[i]+x;
		x=rtn.a[i]/10;
		rtn.a[i]%=10;
	}
	if(x) rtn.a[mx+1]=x,rtn.len++;
	return rtn;
}
gj operator+(gj a,int b)
{
	gj qaq;
    int qwq=b,l=0;
	while(qwq)
	{
		qaq.a[++l]=qwq%10;
		qwq/=10;
	}
	qaq.len=l;
	return a+qaq;
}
void print(gj a)
{
	for(int i=a.len;i>=1;i--)
	 printf("%d",a.a[i]);
	printf("\n"); 
}
int main()
{
	k=read();w=read();int er=1;
	for(int i=1;i<=k;i++) er*=2;
	for(int i=er-1;i>=1;i--) sum[1][i]=sum[1][i+1]+1;
	int n=w/k,nw,sd=er-n;
	for(int i=2;i<=n&&er-i>0;i++)
	{
		int b=i%2;nw=b;
		sum[b][er-i]=sum[b^1][er-i+1];
		for(int j=er-i-1;j>=1;j--) sum[b][j]=sum[b][j+1]+sum[b^1][j+1];
		ans=ans+sum[b][1];
	}
	n=w%k;
	if(!n){print(ans);return 0;}
	er=1;
	for(int i=1;i<=n;i++) er*=2;
	for(int i=1;i<=er-1&&i<sd;i++) ans=ans+sum[nw][i+1];
	print(ans);
}
posted @ 2020-06-10 18:13  千载煜  阅读(327)  评论(0编辑  收藏  举报