zoukankan      html  css  js  c++  java
  • [CF914C] Travelling Salesman and Special Numbers

    [CF914C] Travelling Salesman and Special Numbers - 组合计数

    Description

    对于一个正整数x,我们定义一次操作是将其变为它二进制下“1”的个数。给定n和k,其中n是在二进制下被给出,求出所有不大于n且将其变为1的操作次数为k的数的个数对。(x le 2^{1000})

    Solution

    一个数操作一次以后,一定会变成不超过 1000 的数

    我们先暴力计算出所有不超过 1000 的数的答案

    然后考虑一个类似数位 dp 的过程

    我们去试图把给定数的某个 1 改成 0,那么后面的位置都可以随便选

    在这种可以随便选的情况下,我们就要加上若干个组合数乘以某个不超过 1000 的数的答案是否刚好等于 k 的形式

    这样总的复杂度是 O(n^2) 的,n 为原数的长度

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int mod = 1e9 + 7;
    
    namespace math_mod
    {
        int c__[5005][5005], fac__[5005];
    
        int qpow(int p, int q)
        {
            return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
        }
    
        int inv(int p)
        {
            return qpow(p, mod - 2);
        }
    
        int fac(int p)
        {
            if (p <= 5000)
                return fac__[p];
            if (p == 0)
                return 1;
            return p * fac(p - 1) % mod;
        }
    
        int __fac(int p)
        {
            return fac(p);
        }
    
        int ncr(int n, int r)
        {
            if (r < 0 || r > n)
                return 0;
            return fac(n) * inv(fac(r)) % mod * inv(fac(n - r)) % mod;
        }
    
        void math_presolve()
        {
            fac__[0] = 1;
            for (int i = 1; i <= 5000; i++)
            {
                fac__[i] = fac__[i - 1] * i % mod;
            }
            for (int i = 0; i <= 5000; i++)
            {
                c__[i][0] = c__[i][i] = 1;
                for (int j = 1; j < i; j++)
                    c__[i][j] = c__[i - 1][j] + c__[i - 1][j - 1], c__[i][j] %= mod;
            }
        }
    
        int __c(int n, int r)
        {
            if (r < 0 || r > n)
                return 0;
            if (n > 5000)
                return ncr(n, r);
            return c__[n][r];
        }
    }
    
    using namespace math_mod;
    
    int f[1005], a[1005], n;
    
    void solve_1000()
    {
        f[1] = 0;
        for (int i = 2; i <= 1000; i++)
        {
            int cnt = __builtin_popcount(i);
            f[i] = f[cnt] + 1;
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        solve_1000();
    
        math_presolve();
    
        string str;
        cin >> str;
        int k;
        cin >> k;
    
        if (k == 0)
        {
            cout << 1 << endl;
            return 0;
        }
    
        n = str.length();
        for (int i = 1; i <= n; i++)
            a[i] = str[i - 1] == '1';
    
        int ans = 0;
        int sum = 0; // previous 1-count
    
        // enum the first different position
        for (int i = 1; i <= n; i++)
        {
            // if a[i]==0, then no contribution
            if (a[i] == 0)
                continue;
            // if a[i]==1, then the rest positions can be filled with any digits
            int res = n - i;
            for (int j = 0; j <= res; j++)
            {
                // choose j positions in rest positions to fill with 1
                int cnt = j + sum; // total 1 count
                int val = f[cnt] + 1;
                if (val == k)
                {
                    // ok, make countribution
                    ans += __c(res, j);
                    ans %= mod;
                }
            }
            sum++;
        }
    
        // add itself
        if (f[sum] + 1 == k)
            ans++, ans %= mod;
    
        if (k == 1)
            ans = (ans - 2 + mod) % mod;
    
        cout << ans << endl;
    }
    
  • 相关阅读:
    交友app
    xcode5修改APP名字
    xcode5下取消ARC
    五语言学习系列 C,C++,Objective-C,Java,C# (一)历史
    IT领域的罗马帝国——微软公司
    IBOutlet loadView UIButton的subview数量 UIWebView
    UIColor用自定义颜色,TableView去掉背景色
    ORA-00937: not a single-group group function
    向一张表批量插入值
    lsnrctl start 报错
  • 原文地址:https://www.cnblogs.com/mollnn/p/14485135.html
Copyright © 2011-2022 走看看