POJ 2100 Graveyard Design ( 尺取法 )

题意:

某个数可以表示成连续的数的平方和,求出n有多少种这样的表示方法。

求表示方法按连续数的个数递减排列。

 

分析:

先算出大于等于n的连续数的和。如果等于则更新答案并且左端点++(更新左端点),小于则右端点++

大于则左端点++。

当右端点大于ll(sqrt(n+0.5)+3)时跳出循环  

 

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <map>
 7 #include <vector>
 8 
 9 using namespace std;
10 
11 typedef long long ll;
12 map<int, vector<int> > ans;
13 vector<int> w;
14 vector<int> num;
15 bool cmp(int x,int y)
16 {
17     return x>y;
18 }
19 
20 void solve(ll n)
21 {
22     num.clear();
23     ans.clear();
24     ll sum = 0;
25     ll j = 1,i = 1;
26 
27     while(j<=(ll)(sqrt(n+0.5)+3) && sum<n)
28     {
29         sum += j*j;
30         j++;
31     }
32     while(1)
33     {
34         if(sum==n)
35         {
36             for(int k=i;k<j;k++)
37                 w.push_back(k);
38             ans.insert(make_pair(w.size(),w));
39             num.push_back(w.size());
40 
41             w.clear();
42             sum -= i*i;
43             i++;
44         }
45         if(j>(ll)(sqrt(n+0.5)+3)) break;
46         if(sum>n)
47         {
48             sum -= i*i;
49             i++;
50         }
51         else if(sum<n)
52         {
53             sum += j*j;
54             j++;
55         }
56     }
57 
58     if(num.size()==0) printf("0\n");
59     else
60     {
61         printf("%d\n",num.size());
62         sort(num.begin(),num.end(),cmp);
63         for(int i=0;i<num.size();i++)
64         {
65             int s = num[i];
66             vector<int> t = (ans.find(num[i]))->second;
67             printf("%d",s);
68             for(int j=0;j<s;j++)
69                 printf(" %d",t[j]);
70             printf("\n");
71         }
72     }
73 }
74 
75 int main()
76 {
77     ll n;
78     while(~scanf("%lld",&n))
79     {
80         solve(n);
81     }
82     return 0;
83 }

 

posted @ 2015-03-25 14:57  fukan  阅读(218)  评论(0编辑  收藏  举报