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 }