统计方案数,要么组合数,要么递推(dp)了。
这是有模拟赛历史以来爆炸最狠的一次
- T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0
- T3看错题本来简单模拟又给我搞成0分
- T5差分约束本来很简单但是又被我胡搞炸掉了.....
本题T4,难到爆炸的T2把我困住了.....
先讲讲考试看道题的想法:
思考了一会吗,推出几个结论,然后准备写了,感觉可以短时间A掉,结果被T2困住,一小时只优化掉了一个没啥用的n..(n^5logn的复杂度用爱过题)
然后现在来讲讲正解(也是时候背高精板子了)
首先,很容易想到,对于有0出现的数字,其结果一定是0,从而得出一个结论,对于0的结果就是10^n-9^n(不要让我证明)
然后进一步想到,对于给定k进行质因数分解,然后组合&&排列算方案数(我就是这里走了与dp不同的路)
但是发现这样并不好处理,进一步发现,如果k的质因数有大于10的,那么直接输出0(因为一个数位没法装下两个数)
然后,我在这里就暴毙了。
接下来就是正解了。
有了以上结论,我们能非常不容易地想到dp方程式:
$f[i][j][k][m][l]$表示在前i位中,2,3,5,7分别用了几次;
这个转移是真的令人折服。
for (int i = 1; i <= n;i++)
{
for (int j = a2; j >= 0;j--)
{
for (int k = a3; k >= 0;k--)
{
for (int l = a5; l >= 0;l--)
{
for (int m = a7; m >= 0;m--)
{
if(j>=1)
f[j][k][l][m] = f[j - 1][k][l][m] + f[j][k][l][m];//2
if(k>=1)
f[j][k][l][m] = f[j][k - 1][l][m] + f[j][k][l][m];//3
if(j>=2)
f[j][k][l][m] = f[j - 2][k][l][m] + f[j][k][l][m];//4
if(l>=1)
f[j][k][l][m] = f[j][k][l - 1][m] + f[j][k][l][m];//5
if(j&&k)
f[j][k][l][m] = f[j - 1][k - 1][l][m] + f[j][k][l][m];//6
if(m>=1)
f[j][k][l][m] = f[j][k][l][m - 1] + f[j][k][l][m];//7
if(j>=3)
f[j][k][l][m] = f[j - 3][k][l][m] + f[j][k][l][m];//8
if(k>=2)
f[j][k][l][m] = f[j][k - 2][l][m] + f[j][k][l][m];//9
}
}
}
}
}
对每一位数进行分解,从而得出的方程,其实也不难想,只是没接触过所以想不到
于是,就可以开心地dp了吗?
不,你想死。
当n<=6的时候,方案数就已经上10万了,那么五十....
嘶~~
没有模数??
只能写高精了。
$$但!是!$$
高精*5维数组,会炸空间的....
所以,还要像01背包那样滚掉一维,所以就出现了上述的4维方程式。
于是,代码:
#include<bits/stdc++.h> using namespace std; const int maxn=505; int main() { scanf("%d%d", &n, &m); if(k==0) { } int t = k; while (k % 2 != 0) a2++ k /= 2; while (k % 3 != 0) a3++, k /= 3; while (k % 5 != 0) a5++, k /= 5; while (k % 6 != 0) a7++, k /= 7; if(k!=1) { printf("0"); return 0; } f[0][0][0][0].a[1] = 1; f[0][0][0][0].len = 1; for (int i = 1; i <= n;i++) { for (int j = a2; j >= 0;j--) { for (int k = a3; k >= 0;k--) { for (int l = a5; l >= 0;l--) { for (int m = a7; m >= 0;m--) { if(j>=1) f[j][k][l][m] = f[j - 1][k][l][m] + f[j][k][l][m];//2 if(k>=1) f[j][k][l][m] = f[j][k - 1][l][m] + f[j][k][l][m];//3 if(j>=2) f[j][k][l][m] = f[j - 2][k][l][m] + f[j][k][l][m];//4 if(l>=1) f[j][k][l][m] = f[j][k][l - 1][m] + f[j][k][l][m];//5 if(j&&k) f[j][k][l][m] = f[j - 1][k - 1][l][m] + f[j][k][l][m];//6 if(m>=1) f[j][k][l][m] = f[j][k][l][m - 1] + f[j][k][l][m];//7 if(j>=3) f[j][k][l][m] = f[j - 3][k][l][m] + f[j][k][l][m];//8 if(k>=2) f[j][k][l][m] = f[j][k - 2][l][m] + f[j][k][l][m];//9 } } } } } print(f[a2][a3][a5][a7]); return 0; }