CSP/NOIP新赛制内部挑战赛2 A. 二进制王国
sub1 (50pts)
设f[i][j] 为用前i种纸币,还需要总金额为j的方案数
枚举第i个纸币用了k 张,从f[i−1][j+k∗(2^i)] 转移
时间复杂度:O(n^2*log n)
sub2 (85pts)
其实就是无限背包的问题
直接 f[i][j]=f[i−1][j]+f[i][j+(2^i)]
第一维显然可以压缩掉
时间复杂度:O(n*log n)
sub3 (95pts)
面值为1 的纸币考虑完后,j 为奇数的位置就不可能转移到答案了
面值为2 的纸币考虑完后,j mod 4 != 0 的位置就不可能转移到答案了
后面的以此类推
所以转移有效位置即可
时间复杂度:O(N)
标算
其上一种算法的空间会炸、
观察转移的过程,可以发现程序等价于每次转移后把坐标为奇数的位置删除,然后把n/ = 2
另外容易发现,使用面值为1 的纸币时的转移相当于把数组的每个位置赋值成1
那么我们可以手动完成面值为1 的纸币的转移,时空常数均除以2
注意哈:面值为0也是一种方案!!
代码
#include<bits/stdc++.h> using namespace std; const int maxn=1e8+5; unsigned int f[maxn]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); f[1]=2; int n; scanf("%d",&n); if(!n) { printf("1"); return 0; } n>>=1; for(int i=2;i<=n;i++) f[i]=f[i-1]+f[i>>1]; printf("%u",f[n]); return 0; }