ZOJ--3149(树上统计,数学)
2015-01-01 12:08:34
思路:嘛...其实这是一道数学题...
把图画一通就会发现:当前时间产生的新节点个数是前k个时间内产生的新节点的数量和,因为前k个时间内新产生的节点在当前时间仍能产生新节点(因有限制k)
那么就可以维护一个前缀和sum和当前新结点数val,val = sum[i - 1] - (i - k - 1 > 0 ? sum[i - k - 1] : 0),val[1] = 1,val[0] = 1,表示时间0产生了1个新节点,所以在时间1才有初始节点。
因为超过1234567890就结束,所以答案并不会很大,sum增长非常快为指数级(除了k==0的情况,需特判),数组不必很大。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <iostream> 11 #include <algorithm> 12 using namespace std; 13 #define lp (p << 1) 14 #define rp (p << 1|1) 15 #define getmid(l,r) (l + (r - l) / 2) 16 #define MP(a,b) make_pair(a,b) 17 typedef long long ll; 18 typedef unsigned long long ull; 19 typedef pair<int,int> pii; 20 const int INF = (1 << 30) - 1; 21 const ll limit = 1234567890LL; 22 23 ll sum[100010],val[100010]; 24 ll n,k; 25 26 int main(){ 27 while(cin >> n >> k){ 28 if(n == 0) break; 29 if(k == 0){ 30 cout << min(n - 1,limit + 1) << endl; 31 continue; 32 } 33 memset(val,0,sizeof(val)); 34 ll ans = 0; 35 val[0] = val[1] = sum[1] = 1LL; 36 for(ll i = 2; i <= n; ++i){ 37 val[i] = sum[i - 1]; 38 if(i - k - 1 > 0) val[i] -= sum[i - k - 1]; 39 sum[i] = sum[i - 1] + val[i]; 40 ans += sum[i - 1]; 41 if(ans > limit) break; 42 } 43 cout << ans << endl; 44 } 45 return 0; 46 }