zoukankan      html  css  js  c++  java
  • 1585: 【例 1】Amount of Degrees

    1585: 【例 1】Amount of Degrees

    时间限制: 1000 ms 内存限制: 524288 KB
    提交数: 683 通过数: 360
    【题目描述】
    原题来自:NEERC 2000 Central Subregional,题面详见 Ural 1057。

    求给定区间 [X,Y] 中满足下列条件的整数个数:这个数恰好等于 K 个互不相等的 B 的整数次幂之和。例如,设 X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意:

    17=24+20
    18=24+21
    20=24+22
    【输入】
    第一行包含两个整数 X 和 Y,接下来两行包含整数 K 和 B。

    【输出】
    只包含一个整数,表示满足条件的数的个数。

    【输入样例】
    15 20
    2
    2
    【输出样例】
    3
    【提示】
    数据范围与提示:

    对于全部数据,1≤X≤Y≤231−1,1≤K≤20,2≤B≤10。

    思路:
    数位dp原来不只是4维的qwq
    f[i][j]表示枚举到第i位,当前有j个1的方案数
    转移:f[i][j]=f[i-1][j]+[i-1][j-1]//表示放或者不放
    注意,既然可以放也可以不放,那么必须满足对于当前这一位没有上界限制,即当前位数上的数>=2,如果当前位数上正好=1,那么就说明已经达到了上界,但是我们的dp是依赖没有达到上界来完成的,所以不可以转移,我们就直接把这一位当做0,然后f[i][k]=f[i-1][k],这样的话就满足未达到上界的条件啦。

    注意!!!从高位到低位枚举!!!倒序!!!

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 35
    using namespace std;
    
    ll x,y,k,b;
    ll f[maxn][maxn],num;
    ll c[maxn];
    
    void prepare()
    {
    	memset(f,0,sizeof(f));
    	f[0][0]=1;
    	for(int i=1;i<=31;i++)
    	{
    		f[i][0]=1;
    		for(int j=1;j<=i;j++)
    		{
    			f[i][j]=f[i-1][j-1]+f[i-1][j];
    		}
    	}
    }
    
    ll work(ll x,ll k)
    {
    	ll cnt=0;
    	ll ans=0;
    	while(x)
    	{
    		c[++cnt]=x%b;
    		x/=b;
    	}
    	
    	for(int i=cnt;i>=1;i--)
    	{
    		if(c[i]>1)
    		{
    			ans+=f[i-1][k]+f[i-1][k-1];
    			break;
    		}
    		else if(c[i]==1)
    		ans+=f[i-1][k],k--;
    		if(k<0) break;
    	}
    	
    	return ans;
    	
    }
    
    int main()
    {
    	scanf("%lld%lld%lld%lld",&x,&y,&k,&b);
    	prepare();
    	printf("%lld",work(y+1,k)-work(x,k));
    }
    

    数位dp不难!!!
    我才发现我不会的原因是我没用记忆化+dfs!!

    #include<bits/stdc++.h>
    #define maxn 35
    #define ll long long
    using namespace std;
    
    ll f[maxn][maxn],c[maxn],x,y;
    ll k,b,cnt;
    
    ll dfs(ll n,ll num,bool up)
    {
    	if(n==0) return num==k;
    	if(~f[n][num]&&!up) return f[n][num];
    	int lim=up?c[n]:b-1;
    	ll tmp=0;
    	for(int i=0;i<=min(lim,1);i++)
    	{
    		tmp+=dfs(n-1,num+(i==1),up&&(i==lim));
    	}
    	if(!up) f[n][num]=tmp;
    	return tmp;
    }
    
    ll work(ll x)
    {
    	cnt=0;
    	while(x)
    	{
    		c[++cnt]=x%b;
    		x/=b;
    	}
    	
    	return dfs(cnt,0,1);
    	
    }
    
    int main()
    {
    	memset(f,-1,sizeof(f)); 
    	cin>>x>>y;
    	cin>>k>>b;
    	cout<<work(y)-work(x-1)<<'
    ';
    	return 0;
    }
    
  • 相关阅读:
    变参宏 __VA_ARGS__
    预处理中的 # 和 ##
    strlen与sizeof异同
    .vimrc
    sudo:有效用户 ID 不是 0,sudo 属于 root 并设置了 setuid 位吗
    远程ssh登陆时报错:/bin/bash: Permission denied
    Excel中VBA进行插入列、格式化、排序
    ORACLE发送带附件邮件的二三事之一
    Windows Server 2008 双网卡同时上内外网 不能正常使用
    VMWARE修改CPUID
  • 原文地址:https://www.cnblogs.com/yxr001002/p/14436320.html
Copyright © 2011-2022 走看看