链接
http://acm.hdu.edu.cn/showproblem.php?pid=6125
题解
这题太神辣!
所谓不被平方数整除,其实就是在乘积的质因数分解中,每个质数的幂次不超过
1
1
1
但是质数那么多…就不知道该如何下手
默默点开题解
发现有一点很重要的性质我似乎没想到
每个数
x
x
x都至多有一个大于
x
\sqrt x
x的质因子
不超过
500
500
500的素数有
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
2,3,5,7,11,13,17,19
2,3,5,7,11,13,17,19,就这
8
8
8个
先把本身就带平方因子的数字删掉
剩下的数,每个都可以被表示为这
8
8
8个素数乘以一个大质数的形式(也可能没有大质数)
如果用一个二进制数
s
s
s表示每个小素数选没选,那么每个数都可以表示成
s
,
t
s,t
s,t,其中
t
t
t是除掉小素数之后的数(要么是1要么是一个大素数)
那么每个数就表示成了
(
s
i
,
t
i
)
(s_i,t_i)
(si,ti)
原来的条件就等价于:选择的数中,对于任意的
i
,
j
i,j
i,j,都满足
s
i
&
s
j
=
0
s_i\&s_j=0
si&sj=0而且
t
i
=
̸
t
j
t_i =\not t_j
ti≠tj
那么我把
t
t
t相同的分到一组中,相当于每个组只能至多一个数字
d
p
dp
dp的时候分组,就能保证大质数肯定不相等
然后所有数字再满足
s
i
&
s
j
=
0
s_i\&sj=0
si&sj=0
注意
t
=
1
t=1
t=1要特殊处理
d
p
i
j
k
dp_{ijk}
dpijk表示前
i
i
i个组,选了
j
j
j个数字,素数的选择状态为
k
k
k的方案数
d
p
dp
dp的时候一组一组往里加就行了
题外话
在火车上写代码真的是要吐了
本来不晕火车的,这个程序敲完我都晕火车了
代码
#include <bits/stdc++.h>
#define maxn 510
#define mod 1000000007ll
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return f*x;
}
ll dp[2][maxn][maxn];
vector<ll> cat[maxn];
int main()
{
ll i, j, k, N, K, T(read());
vector<ll> p{2,3,5,7,11,13,17,19};
while(T--)
{
N=read(), K=read();
for(i=1;i<=N;i++)cat[i].clear();
for(i=1;i<=N;i++)
{
auto t(i), s(0ll);
bool ok=true;
for(auto x:p)if(i%(x*x)==0)ok=false;
if(!ok)continue;
for(j=0;j<p.size();j++)if(t%p.at(j)==0)s|=1<<j, t/=p.at(j);
cat[t].emplace_back(s);
}
cl(dp);
auto f=dp[1];
f[0][0]=1;
for(auto s:cat[1])
{
for(j=cat[1].size()-1;j>=0;j--)for(k=0;k<(1<<8);k++)
{
if((s&k)==0)(f[j+1][k|s]+=f[j][k])%=mod;
}
}
for(i=1;i<N;i++)
{
auto &f=dp[i&1], &g=dp[i&1^1];
cl(g);
for(j=0;j<=K;j++)for(k=0;k<(1<<8);k++)
{
(g[j][k]+=f[j][k])%=mod;
for(auto s:cat[i+1])
if((k&s)==0)(g[j+1][k|s]+=f[j][k])%=mod;
}
}
ll ans=0;
for(j=1;j<=K;j++)for(k=0;k<(1<<8);k++)(ans+=dp[N&1][j][k])%=mod;
cout<<ans<<endl;
}
return 0;
}