 /**//*
給定一個n < 2^31
在[1,n]中選出一些數(shù),每個數(shù)可以選多個, 但要求他們的和為n
而且只用這些數(shù)能唯一表示[1,n]中所有的數(shù)
如n = 5, 有{1,1,1,1,1} {1,2,2} , {1,1,3}

看到n這么大,應該是數(shù)學之類的方法或者logn,sqrt(n)之類的
想不出怎么縮小規(guī)模 -_,-

看這里的
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],則接下來的數(shù)就是k+1
如果有1個k+1,則[1,2k+1]都能被表示了,所以下一個數(shù)只能是2(k+1)
如果有2個k+1,則[1,3k+2]都能被表示了,所以下一個數(shù)只能是3(k+1)

但無論如何,接下來的數(shù)只能是t(k+1)
所以這個集合,除了k個1之外,其他數(shù)都是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記錄下結(jié)果

但解題報告那里是對n分解質(zhì)因子為∏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
搜索
最新評論

|
|