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
",solve(n,k));
    }
    return 0;
}
/*
2
4 2
6 4
*/
原文地址:https://www.cnblogs.com/zxhl/p/7383875.html