数的度量——一道计数问题的三种做法

https://www.acwing.com/problem/content/description/1083/

度的数量

求给定区间 [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

输出格式

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

数据范围

1≤X≤Y≤231−1

,
1≤K≤20,
2≤B≤10

 

输入样例:

15 20
2
2

输出样例:

3
难度: 中等
时/空限制: 1s / 64MB
总通过数: 195
总尝试数: 382
来源: 《信息学奥赛一本通》 , Ural 1057
算法标签

 

 

将问题放在B进制意义下考虑,即求在[l, r]的区间内有K个位是1,其余位是0的数。

求得[0, r]满足的数为S(r)个,[0, l - 1]满足的数为S(l - 1)个,最后答案即为S(r) - S(l - 1)。

求S(x)的方法如下:

1,数位DP。

设f[i][j]表示在最高位到第i位这一段中,使用了j个1,且小于X在这一段表示的数,的所有方案数。

g[i][j]表示在最高位到第i位这一段中,使用了j个1,且等于X在这一段表示的数(即这一段的数字完全相同),的所有方案数(显然要么为0,要么为1)。

分情况讨论转移即可。

最后答案为f[1][K] + g[1][K]。

#include 
#include 
#include 
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN = 40;
int l, r, K, B;
int f[MAXN][MAXN], g[MAXN][MAXN];
int a[MAXN];
int work(int x)
{
    memset(f, 0, sizeof f);
    memset(g, 0, sizeof g);
    int i, j, ans, n = 0;
    while(x){
        a[++n] = x % B;
        x /= B;
    }
    g[n + 1][0] = 1;
    f[n + 1][0] = 0;
    ff(i, n, 1){
        f[i][0] = 1;
        if(!a[i]) g[i][0] = g[i + 1][0];
        f(j, 1, min(K, n - i + 1)){
            f[i][j] = f[i + 1][j] + f[i + 1][j - 1];
            if(a[i]){
                f[i][j] += g[i + 1][j];
                if(a[i] > 1){
                    f[i][j] += g[i + 1][j - 1];
                }
                else{
                    g[i][j] = g[i + 1][j - 1];
                }
            }
            else{
                g[i][j] = g[i + 1][j];
            }
        }
    }
    return f[1][K] + g[1][K];
}
int main()
{
    int i;
    cin >> l >> r >> K >> B;
    cout << work(r) - work(l - 1) << endl;
    return 0;
}

2,记忆化搜索。

搜索时记录当前在哪一位,使用了几个1,当前这一段是否小于原数。

#include 
#include 
#include 
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN = 40;
int l, r, K, B;
int f[MAXN][MAXN][2];
int a[MAXN];
int dfs(int cur, int num, int tag)
{
    int &v = f[cur][num][tag];
    if(~ v) return v;
    if(cur < K - num || num > K) return v = 0;
    if(cur == 0 && num == K) return v = 1;
    v = 0;
    if(a[cur]){
        v += dfs(cur - 1, num, tag | 1);
        if(a[cur] > 1){
            v += dfs(cur - 1, num + 1, tag | 1);
        }
        else{
            v += dfs(cur - 1, num + 1, tag);
        }
    }
    else{
        v += dfs(cur - 1, num, tag);
        if(tag){
            v += dfs(cur - 1, num + 1, tag);
        }
    }
    return v;
}
int work(int x)
{
    memset(f, -1, sizeof f);
    int i, j, ans, n = 0;
    while(x){
        a[++n] = x % B;
        x /= B;
    }
    return dfs(n, 0, 0);
}
int main()
{
    int i;
    cin >> l >> r >> K >> B;
    cout << work(r) - work(l - 1) << endl;
    return 0;
}

3,组合计数。

考虑最高位。

1,若最高位小于原数,则其余位1的位置可以任意放,方案位c(n,m)(剩余有n位,要放m个1)

2,若最高位等于原数,则移到次高位,递归进行这两个步骤。

#include 
#include 
#include 
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int MAXN = 40;
int l, r, K, B;
int f[MAXN][MAXN];
int C[MAXN + 1][MAXN + 1];
int a[MAXN];
void init()
{
    int i, j;
    f(i, 0, MAXN){
        C[i][0] = 1;
        f(j, 1, i){
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
    }
}
int work(int x)
{
    init();
    int i, j, ans, n = 0;
    while(x){
        a[++n] = x % B;
        x /= B;
    }
    int res = 0, cnt = 0;
    ff(i, n, 1){
        if(a[i]){
            res += C[i - 1][K - cnt];
            if(a[i] > 1){
                if(K - cnt - 1 > 0){
                    res += C[i - 1][K - cnt - 1];
                }
                break;
            }
            else{
                cnt ++;
                if(cnt > K){
                    break;
                }
            }
        }
    }
    if(i == 0 && cnt == K) res ++;
    return res;
}
int main()
{
    int i;
    cin >> l >> r >> K >> B;
 //   cout << work(r) << endl;
    cout << work(r) - work(l - 1) << endl;
    return 0;
}

 

你可能感兴趣的:(动态规划,数学)