zoukankan      html  css  js  c++  java
  • CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述
      我们把一个数称为有趣的,当且仅当:
      1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
      2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
      3. 最高位数字不为0。
      因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
      请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。
    输入格式
      输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。
    输出格式
      输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。
    样例输入
    4
    样例输出
    3
     
    析:先说第一种方法,数位DP:
    首先只有0123,并且有约束条件,那么就只有6种状态,{2},{20},{201},{23},{203},{2031},然后依次对每一位进行计算即可。
    第二种,状压DP:
    因为只有4种数字,所以可能用状压DP,1表示0, 2表示1, 4表示2,8表示3.剩下的就简单了。
    第三种,组合数学+暴力枚举:
    先枚举01的数量,那么最少2个,最多n-2个,由于0是不能放在首位,所以就有c(n-1, i),i 表示有多少个01,然后再考虑有多种方法,
    应该有 n-i 种方法,因为0的数量是从1个到 i-1 个,同理,23就有 n-i-1 种,然后乘起来就好。
    第四种,推公式:
    这个方法和第三种一样的,只不过是把第三种简化了,然后成一个递推公式,an=(n*n-5n+4)*2^(n-3)+n-1。
    第五种,矩阵快速幂:
    对每一个组成数字进行分析,字符串必定以2开头,把字符串中字符放入一个集合,我们可以统计长度为N,字符集合为S的合法字符串个数,
    然后把它们的关系表示成一个矩阵,就OK了。
     
    代码如下:
    数位DP:
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <stack>
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const LL LNF = 100000000000000000;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int mod = 1e9 + 7;
    const char *mark = "+-*";
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, 1, 0, -1};
    int n, m;
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    inline LL Max(LL a, LL b){  return a < b ? b : a; }
    inline LL Min(LL a, LL b){  return a > b ? b : a; }
    inline int Max(int a, int b){  return a < b ? b : a; }
    inline int Min(int a, int b){  return a > b ? b : a; }
    LL dp[maxn][5];
    
    int main(){
        while(cin >> n){
            dp[4][0] = 7;  dp[4][1] = 5; dp[4][2] = 3;  dp[4][3] = 9;  dp[4][4] = 3;
            for(int i = 5; i <= n; ++i){
                dp[i][0] = (1 + 2 * dp[i-1][0]) % mod;
                dp[i][1] = (dp[i-1][0] + 2 * dp[i-1][1]) % mod;
                dp[i][2] = (1 + dp[i-1][2]) % mod;
                dp[i][3] = (dp[i-1][0] + dp[i-1][2] + 2 * dp[i-1][3]) % mod;
                dp[i][4] = (dp[i-1][1] + dp[i-1][3] + 2 * dp[i-1][4]) % mod;
            }
            cout << dp[n][4] << endl;
        }
    }
    

    状压DP:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #define frer freopen("in.txt", "r", stdin)
    #define frew freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 1, 0, 0};
    const int dc[] = {0, 0, 1, -1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int Min(int a, int b){ return a < b ? a : b; }
    inline int Max(int a, int b){ return a > b ? a : b; }
    inline LL Min(LL a, LL b){ return a < b ? a : b; }
    inline LL Max(LL a, LL b){ return a > b ? a : b; }
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    LL dp[maxn][(1<<4)+1];
    
    int main(){
        while(cin >> n){
            memset(dp, 0, sizeof dp);
            dp[0][0] = 1;
            for(int i = 0; i < n; ++i){
                for(int j = 0; j < 16; ++j){
                    if(!dp[i][j])  continue;
                    if(!(j & 2) && i)  dp[i+1][j|1] = (dp[i+1][j|1] + dp[i][j]) % mod;
                    dp[i+1][j|2] = (dp[i+1][j|2] + dp[i][j]) % mod;
                    if(!(j & 8))  dp[i+1][j|4] = (dp[i+1][j|4] + dp[i][j]) % mod;
                    dp[i+1][j|8] = (dp[i+1][j|8] + dp[i][j]) % mod;
                }
            }
            cout << dp[n][15] << endl;
        }
        return 0;
    }
    

    组合数学+暴力枚举:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #define frer freopen("in.txt", "r", stdin)
    #define frew freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 1, 0, 0};
    const int dc[] = {0, 0, 1, -1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int Min(int a, int b){ return a < b ? a : b; }
    inline int Max(int a, int b){ return a > b ? a : b; }
    inline LL Min(LL a, LL b){ return a < b ? a : b; }
    inline LL Max(LL a, LL b){ return a > b ? a : b; }
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    LL c[maxn][maxn];
    void init(){
        for(int i = 0; i < n; ++i) c[i][0] = c[i][i] = 1;
        for(int i = 2; i < n; ++i)
            for(int j = 1; j < i; ++j)
                c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
    }
    
    int main(){
        while(cin >> n){
            init();
            LL ans = 0;
            for(int i = 2; i < n-1; ++i)
                ans = (ans + (c[n-1][i] * (i-1) * (n-i-1))  % mod) % mod;
            cout << ans << endl;
        }
        return 0;
    }
    

    推公式:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #define frer freopen("in.txt", "r", stdin)
    #define frew freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 1, 0, 0};
    const int dc[] = {0, 0, 1, -1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int Min(int a, int b){ return a < b ? a : b; }
    inline int Max(int a, int b){ return a > b ? a : b; }
    inline LL Min(LL a, LL b){ return a < b ? a : b; }
    inline LL Max(LL a, LL b){ return a > b ? a : b; }
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    LL quick_pow(LL a, LL b){
        LL ans = 1;
        while(b){
            if(b & 1)  ans = (ans * a) % mod;
            b >>= 1;
            a = (a * a) % mod;
        }
        return ans;
    }
    
    int main(){
        while(cin >> n){
            LL ans = (n * n - 5 * n + 4) % mod;
            ans = (ans * quick_pow(2LL, n-3) + n - 1) % mod;
            cout << ans << endl;
        }
        return 0;
    }
    

    矩阵快速幂:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #define frer freopen("in.txt", "r", stdin)
    #define frew freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    const double inf = 0x3f3f3f3f3f3f;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e3 + 5;
    const int mod = 1e9 + 7;
    const int dr[] = {-1, 1, 0, 0};
    const int dc[] = {0, 0, 1, -1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int Min(int a, int b){ return a < b ? a : b; }
    inline int Max(int a, int b){ return a > b ? a : b; }
    inline LL Min(LL a, LL b){ return a < b ? a : b; }
    inline LL Max(LL a, LL b){ return a > b ? a : b; }
    inline bool is_in(int r, int c){
        return r >= 0 && r < n && c >= 0 && c < m;
    }
    struct Matrix{
        LL a[6][6];
    };
    
    Matrix mul(Matrix x, Matrix y){
        Matrix ans;
        memset(ans.a, 0, sizeof ans.a);
        for(int i = 0; i < 6; ++i){
            for(int j = 0; j < 6; ++j){
                for(int k = 0; k < 6; ++k){
                    ans.a[i][j] += (x.a[i][k] * y.a[k][j]) % mod;
                }
                ans.a[i][j] %= mod;
            }
        }
        return ans;
    }
    
    Matrix quick_pow(Matrix x, int b){
        Matrix ans;
        memset(ans.a, 0, sizeof ans.a);
        for(int i = 0; i < 6; ++i)
                ans.a[i][i] = 1;
        while(b){
            if(b & 1)  ans = mul(ans, x);
            b >>= 1;
            x = mul(x, x);
        }
        return ans;
    }
    
    int main(){
        Matrix x, y;
        memset(x.a, 0, sizeof x.a);
        memset(y.a, 0, sizeof y.a);
        x.a[3][3] = x.a[0][0] = x.a[1][0] = x.a[2][1] = x.a[3][0] = x.a[4][1] = x.a[4][3] = x.a[5][2] = x.a[5][4] = x.a[5][5] = 1;
        x.a[1][1] = x.a[4][4] = x.a[5][5] = x.a[2][2] = 2;
        y.a[0][0] = 1;
        while(cin >> n){
            Matrix ans = mul(quick_pow(x, n-1), y);
            cout << ans.a[5][0] << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    JAVA中SESSION和COOKIE的解释
    关于org.apache.catalina.session.StandardManager doLoad错误的解决
    MySQL 修改字段类型或长度
    JS倒计时 定时器
    设置tomcat内存
    Unable to resolve JRE: jdk1.6.0_01 (Standard VM)
    Error configuring application listener of class org.springframework.web.context.ContextLoader
    nested exception is java.lang.OutOfMemoryError: PermGen space
    导数据,整理数据思路总结
    mysql_mssql_access_2017年最新手机号段归属地数据库(17年4月更新)360569记录
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5818722.html
Copyright © 2011-2022 走看看