• HDU 6125


    思路来自这里 - -

    /*
    HDU 6125 - Free from square [ 分组,状压,DP ]  |  2017 Multi-University Training Contest 7
    题意:
    	不超过N的数字中选K个,其乘积不是平方数的倍数
    	限制 N,K <= 500
    分析:
    	小于根号N的质因子至多只有8个,而大于根号N的质因子任意两个乘积大于N
    	所以N以内的完全平方数只有两种 
    		1. 没有大于根号N的质因子
    		2. 有且只有1个大于根号N的质因子
    	对于小于根号N的质因子,可以直接按集合状压DP(自身为1组)
    	对于大于根号N的质因子,可以将包含该质因子的 非平方数的倍数的数 都归为1组,然后分组DP
    	每个数字的状态为其所包含的小于根号N的质因子的集合
    	具体DP递推式 为 
    		if (a&b == 0) dp[k][a|b] = (dp[k][a|b] + dp[k-1][b]) % MOD;
    	其中 a, b为小于8的质因子的集合
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int MOD = 1e9+7;
    const int N = 505;
    int p[8] = {2, 3, 5, 7, 11, 13, 17, 19};
    int n, t, k;
    int dp[N][1<<10];
    int st[N], belong[N];
    vector<int> v[N];
    int solve()
    {
        for (int i = 1; i <= n; i++)
        {
            belong[i] = i;
            for (int j = 0; j < 8; j++)
                if (i % p[j] == 0)
                {
                    if (i% (p[j]*p[j]) == 0)
                    {
                        st[i] = -1; break;
                    }
                    st[i] |= 1<<j;
                    belong[i] /= p[j];
                }
            if (st[i] == -1) continue;
            if (belong[i] == 1) v[i].push_back(i);
            else v[belong[i]].push_back(i);
        }
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++)
        {
            if (st[i] == -1 || v[i].size() == 0) continue;
            for (int l = k; l >= 1; l--)
                for (int j = 0; j < (1<<8); j++)
                    for (auto & x : v[i])
                    {
                        int p = st[x];
                        if (!(p&j)) dp[l][p|j] = (dp[l][p|j] + dp[l-1][j]) % MOD;
                    }
        }
        int ans = 0;
        for (int i = 1; i <= k; i++)
            for (int j = 0; j < (1<<8); j++)
                ans = (ans + dp[i][j]) % MOD;
        return ans;
    }
    int main()
    {
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%d", &n, &k);
            memset(dp, 0, sizeof(dp));
            memset(st, 0, sizeof(st));
            for (int i = 1; i <= n; i++) v[i].clear();
            printf("%d
    ", solve());
        }
    }
    

      

  • 相关阅读:
    点击图片显示原图
    SQL判断语句
    窗口淡入淡出效果
    判断两段时间之间的时间差
    软件行业发展趋势
    VSS客户端不能访问问题“unable to open user login file\\服务器项目管理目录\data\logedin\用户名.log ”
    鑫哥儿子顺利降生了!
    面向对象原则之单一职责原则实现
    PHP编码,乱码问题
    泛型中的default(T)
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/7376091.html
Copyright © 2020-2023  润新知