题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=2833
题解
显然,每种情况都可以转化成:
B
B
B的取值为与XXX......XXX......XXX......
类似的情况,其中位置
i
i
i为X
说明
B
B
B中有
i
i
i,否则没有。
设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示取值范围长度为
i
i
i,需要选
j
j
j个值,
k
=
0
k=0
k=0时连续X
长度为
1
1
1,
k
=
1
k=1
k=1时连续X
长度大于
1
1
1,此时的方案数。
f
[
i
]
[
j
]
[
1
]
=
∑
k
∣
j
,
k
>
1
f
[
i
k
]
[
j
k
]
[
0
]
f
[
i
]
[
j
]
[
0
]
=
f
[
i
]
[
i
j
]
[
1
]
f[i][j][1]=\sum_{k|j,k>1} f[\frac{i}{k}][\frac{j}{k}][0]\\ f[i][j][0]=f[i][\frac{i}{j}][1]
f[i][j][1]=k∣j,k>1∑f[ki][kj][0]f[i][j][0]=f[i][ji][1]
状态数不多,用记搜,map记录状态。
代码
#include <map>
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=1000;
struct data
{
int len,n,k;
data(int _len=0,int _n=0,int _k=0):len(_len),n(_n),k(_k){}
bool operator <(const data &other) const
{
if(len==other.len)
{
if(n==other.n)
{
return k<other.k;
}
return n<other.n;
}
return len<other.len;
}
};
std::map<data,long long> f;
long long getf(data d)
{
if(d.n==1)
{
return 1-d.k;
}
if(f.count(d))
{
return f[d];
}
if(d.k==0)
{
f[d]=getf(data(d.len,d.len/d.n,1));
}
else
{
long long ans=0;
for(int i=1; i*i<=d.n; ++i)
{
if(d.n%i)
{
continue;
}
if(i!=1)
{
ans+=getf(data(d.len/i,d.n/i,0));
}
if(i*i!=d.n)
{
ans+=getf(data(d.len/(d.n/i),d.n/(d.n/i),0));
}
}
f[d]=ans;
}
return f[d];
}
int t,n;
int main()
{
t=read();
while(t--)
{
n=read();
if(n==1)
{
puts("1");
continue;
}
printf("%lld\n",getf(data(n*n,n,1)));
}
return 0;
}