看题:
Given a sequence 1,2,3,…N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.
Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.
一开始看到这道题,想到了递归分治(因为有点像那道max sum),但由于N,M的范围特别大,用这种方法一定超时,动态规划,遍历也一定超时。因此这道题应该有一些技巧,不是硬来的。
后来突然想到了等差数列求和,受次启发,决定根据公式Sn=na1+n(n-1)/2来A题。设子序列起点为a,长度为k,则有如下式子
M=ka+k(k-1)/2;
稍作变形得到:
a=M/k-(k-1)/2;
由于题中所有数字均是正整数,因此我们只要以k为对象,弄一层循环,找出所有M/k-(k-1)/2为整数时的k值就好了。因为a>0,a<=M,所以循坏应从k=1开始,M/k-(k-1)/2结束。
伪代码如下:
long long N;double M;
long long a;double k;
输入N,M
for(k=1;k*(k-1)<2*M;k++)
{ if(M/k-(k-1)/2是整数) 记录k的值}
输出满足条件的k对应子序列。
代码如下:
#include<cstdio>
#include<cmath>
using namespace std;
double array[100005];
int main()
{
long long N;double M;
long long a;double k;
int i,j;
while(~scanf("%lld %lf",&N,&M)&&(N||M))
{
array[0]=a=0;
long long temp;
for(j=0,k=1;k*(k-1)<2.0*M;k++)
{
temp=M/k-(k-1)/2.0;
if(temp==M/k-(k-1)/2.0&&temp<=N)
array[j++]=k;
}
if(array[0]!=0)
{
for(i=j-1;i>=0;i--)
{
a=(long long)( M/array[i]-(array[i]-1)/2.0 );
printf("[%lld,%lld]\n",a,a+(long long)array[i]-1);
}
}
printf("\n");
}
return 0;
}
一遍就AC,有点开森。