/**//* 给定一个n < 2^31 在[1,n]中选出一些数,每个数可以选多个, 但要求他们的和为n 而且只用这些数能唯一表示[1,n]中所有的数 如n = 5, 有{1,1,1,1,1} {1,2,2} , {1,1,3}
看到n这么大,应该是数学之类的方法或者logn,sqrt(n)之类的 想不出怎么缩小规模 -_,-
看这里的 http://knol.google.com/k/wenlei-xie/acm-icpc-dhaka-2007-%E8%A7%A3%E9%A2%98%E6%8A%A5%E5%91%8A/15moho0gp59j7/3#
首先必须有1,然后枚举包含k个1,则能表示[1,k],则接下来的数就是k+1 如果有1个k+1,则[1,2k+1]都能被表示了,所以下一个数只能是2(k+1) 如果有2个k+1,则[1,3k+2]都能被表示了,所以下一个数只能是3(k+1) 但无论如何,接下来的数只能是t(k+1) 所以这个集合,除了k个1之外,其他数都是t(k+1) , t >=1 由于需要和为n,所以k+1 | n-k 所以答案为:f(n) = ∑f((n-k)/(k+1)) = ∑f((n+1)/(k+1)-1) k>=1, k+1 | n-k 边界为f(0) = 1 因此可以枚举n+1的因子,sqrt(n+1)的复杂度,有点慢 用个map记录下结果
但解题报告那里是对n分解质因子为∏pi^ai,用这种方法去枚举因子 厄。。。还没试过 */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<ctime>
using namespace std;
map<unsigned int , long long> mp;
long long solve(unsigned int n) { map<unsigned int , long long>::iterator it = mp.find(n); if (it != mp.end()) { return it->second; } long long ans = 0; for (unsigned int k = 1; k+1 <= (n+1)/(k+1) ; k++) { if ((n+1) % (k+1) == 0) { ans += solve((n+1)/(k+1) - 1); unsigned int kk = (n+1)/(k+1); if (kk != k+1) { ans += solve(k);//k+1-1 } } } return mp[n] = ans + 1; }
int main() { #ifndef ONLINE_JUDGE //freopen("in","r",stdin); #endif
mp[0] = 1; int T, t = 1; for (scanf("%d", &T); T-- ;) { unsigned int n; scanf("%u", &n); printf("Case %d: %lld\n", t++, solve(n)); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|