数论专题

占坑待补。

 

1、数位dp:

数位dp论文

http://wenku.baidu.com/link?url=967OXYqlrJC6X4kHfOIhIloao2vnoX3-V5X45w9q3plRy0D9ifraD_TzPIHj2BrAxrDIHj31bLzcAAnciWOHmvhMnxz3tCMI7v0PIdPDg27

ural 1057

给定区间,统计总和等于k个不相等的b的整数幂的个数。k和b范围1~20。

显然就是数位dp前i位有j个1,但是由于这是b进制,所以需要转换,把边界数字转化为不大于它的最大1组成的b进制。

然后就是借助二叉树这个工具进行思考,每次右转的时候把左子树加进来。

有一个想了很久才想通的问题d[i][j]其实本身不是一个二叉树,而是包含两个二叉树,一个根是0,一个根是1,

但是计算边界对应的答案的时候方便起见用0根。

计算二进制的时候>>1放在a[i]=tmp%b后面了导致二进制多了一位坑了1个半小时

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<sstream>
using namespace std;
#define ll long long
#define LL long long
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define For(i,a,b) for(int i=a;i<=b;i++)
#define ForD(i,a,b) for(int i=b;i>=a;i--)
#define fp freopen("/Volumes/未命名2/Downloads/acm/in.txt","r",stdin)
#define ptarr(a,x,y) for(int _=x;_<=y;_++) if(_!=y) cout<<a[_]<<" ";else cout<<a[_]<<endl;
#define pt1(a) cout<<a<<endl;
#define pt2(a,b) cout<<a<<" "<<b<<endl;
#define pt3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define pt4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
#define ln1 cout<<"----------------------"<<endl;
#define ln2 cout<<"~~~~~~~~~~~~~~~~~~~~~~"<<endl;
struct node{int a, b;bool operator<(const node& rhs)const {if(a==rhs.a) return b<rhs.b;else return a<rhs.a;} };
int T,n,m,K;
ll x,y,k,b;
ll d[100][100];
void read(){
    cin>>x>>y>>k>>b;
}
void preprocess(){

}
int get(ll x,ll k)
{
    ll tmp=x;
    int a[33],last=-1;
    For(i,0,31)
    {
        a[i]=tmp%b;
        if(a[i]>1) last=i;
        tmp/=b;
    }
    if(last!=-1){
        For(t,0,last) a[t]=1;
    }
    x=0;
    ForD(i,0,31)
    {
        x<<=1;
        x|=a[i];
    }
    int tot=0,ans=0;
    // ptarr(a,0,31);
    ForD(i,1,31)
    {
        if(x&(1<<i))
        {
            tot++;
            if(tot>k) break;
            x=x^(1<<i);
        }
        if((1<<(i-1))<=x)
        {
            // pt3(i-1,k-tot,d[i-1][k-tot]);
            ans+=d[i-1][k-tot];
        }
    }
    if(tot+x==k) ++ans;
    // ln1;
    return ans;
}
void solve(){
    d[0][0]=1;
    For(i,1,32)
    {
        d[i][0]=d[i-1][0];
        // pt3(i,0,d[i][0]);
        For(j,1,i)
        {
            d[i][j]=d[i-1][j-1]+d[i-1][j];
            // pt3(i,j,d[i][j]);
        }
    }
    printf("%d\n",-get(x-1,k)+get(y,k));
}
int main()
{
    {
        read();
        solve();
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/diang/p/5954055.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值