HDU 6125 Free from square 状态压缩DP + 分组背包

Free from square

 

Problem Description
There is a set including all positive integers that are not more then  n. HazelFan wants to choose some integers from this set, satisfying: 1. The number of integers chosen is at least 1 and at most k. 2. The product of integers chosen is 'free from square', which means it is divisible by no square number other than 1. Now please tell him how many ways are there to choose integers, module 10^9+7.
 
Input
The first line contains a positive integer  T(1T5), denoting the number of test cases.
For each test case:
A single line contains two positive integers n,k(1n,k500).
 
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
 
Sample Input
2 4 2 6 4
 
Sample Output
6 19
 
题解:
  n个数
  首先你明白,1~n个数,没有数是包含超过两个 大于根号n 的质因子的,
  小于根号n的质因子只有8个,所以做这个题的思路就有了
  对于只含有小于根号n的 那些质因子的那些数,我们状态压缩DP就好了
  对于包含大于根号n 的 那些质因子的 那些数,我们分组背包, 也就是说 某些包含同一个 大于根号n的 因子 放在一组里边
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 5e2+20, M = 1e3+20,inf = 2e9,mod = 1e9+7;

int p[] = {2,3,5,7,11,13,17,19};
vector<int > fi,se[N];
int dp[2][N][(1<<8)+10],f[N];

int solve(int n,int K) {
    fi.clear();
    memset(dp,0,sizeof(dp));
    for(int i = 0; i <= n; ++i) se[i].clear(),f[i] = 0;
    fi.push_back(1);
    for(int i = 2; i <= n; ++i) {
        int tmp = i,now = 0,ok = 1;
        for(int j = 0; j < 8; ++j) {
            int _ = 0;
            while(tmp % p[j] == 0) _++,now|=(1<<j),tmp/=p[j];
            if(_ >= 2) ok = 0;
        }
        if(ok) {
            f[i] = now;
            if(tmp!=1) se[tmp].push_back(i);
            else fi.push_back(i);
        }
    }
    int now = 0;
    dp[0][0][0] = 1;
    for(int i = 0; i < fi.size(); ++i) {

        now ^= 1;memset(dp[now],0,sizeof(dp[now]));
        for(int k = 0; k <= K; ++k) {
            for(int j = 0; j < (1<<8); ++j) {

                dp[now][k][j] += dp[now^1][k][j];
                dp[now][k][j] %= mod;

                if((j&f[fi[i]])) continue;

                dp[now][k+1][j|f[fi[i]]] += dp[now^1][k][j];
                dp[now][k+1][j|f[fi[i]]] %= mod;

            }
        }
    }

    for(int i = 1; i <= n; ++i) {
        if(se[i].size() == 0) continue;
     //   cout<<"shit"<<endl;
        now^=1;memset(dp[now],0,sizeof(dp[now]));
        for(int h = 0; h <= K; ++h) {
           for(int k = 0; k < (1<<8); ++k) {

               dp[now][h][k] += dp[now^1][h][k];
                  dp[now][h][k] %= mod;

                for(int j = 0; j < se[i].size(); ++j) {
                  if((f[se[i][j]]&k)) continue;
                  dp[now][h+1][f[se[i][j]]|k] += dp[now^1][h][k];
                  dp[now][h+1][f[se[i][j]]|k] %= mod;
                }
            }
        }
    }

    int ans = 0;
    for(int i = 1; i <= K; ++i) {
        for(int j = 0; j < (1<<8); ++j)
            ans += dp[now][i][j],ans %= mod;
    }
    return ans;
}


int main() {
    int T,n,k;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&k);
        printf("%d\n",solve(n,k));
    }
    return 0;
}
/*
2
4 2
6 4
*/

 

转载于:https://www.cnblogs.com/zxhl/p/7383875.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值