hdu 4982 Goffi and Squary Partition(BestCoder Round #6)

Goffi and Squary Partition

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 428    Accepted Submission(s): 160


Problem Description
Recently, Goffi is interested in squary partition of integers.

A set \(X\) of \(k\) distinct positive integers is called squary partition of \(n\) if and only if it satisfies the following conditions:
[ol]
  • the sum of \(k\) positive integers is equal to \(n\)
  • one of the subsets of \(X\) containing \(k - 1\) numbers sums up to a square of integer.[/ol]
    For example, a set {1, 5, 6, 10} is a squary partition of 22 because 1 + 5 + 6 + 10 = 22 and 1 + 5 + 10 = 16 = 4 × 4.

    Goffi wants to know, for some integers \(n\) and \(k\), whether there exists a squary partition of \(n\) to \(k\) distinct positive integers.
  •  

    Input
    Input contains multiple test cases (less than 10000). For each test case, there's one line containing two integers \(n\) and \(k\) (\(2 \le n \le 200000, 2 \le k \le 30\)).
     

    Output
    For each case, if there exists a squary partition of \(n\) to \(k\) distinct positive integers, output "YES" in a line. Otherwise, output "NO".
     

    Sample Input
       
       
       
       
    2 2 4 2 22 4
     

    Sample Output
       
       
       
       
    NO YES YES
     


    BestCoder 官方题解:

        

    给你N和K,问能否将N拆分成K个互不相同的正整数,并且其中K-1个数的和为完全平方数
    
    PS:这道题目原来是要求输出一种可行方案的,所以下面题解是按照输出方案的思想搞的。
    分析:
    我们尝试枚举那个完全平方数 S,然后看能否将他拆分为 K-1 个数,并且不用到N-S
    这一步可以用贪心+一次调整来搞定。为了保证 K-1 个数都不同,我们尝试尽量用 1,2,3...这些连续自然数来构造,如果 N-S 出现在这些数中,那么将 N-S 移除,再新加一个数。如果这样都不能拆分成 K-1 个数,那么这个 S 肯定不行。
    现在考虑已经用上述方法拆分了,我们需要判断这个拆分是否可行。会产生问题的只有最后一个数,这个数可能和 N-S 一样,也可能出现在之前的序列。如果是出现在之前的序列,那么这个拆分也是不靠谱的。如果和 N-S 一样,那么分两种情况
    1.	N-S 曾出现在之前的序列,那么显然这个拆分也是不靠谱的
    2.	N-S 比倒数第二个数大,对于这种我们可以通过调整最后一个数和倒数第二个数的大小,来使得这个拆分成立,假设最后一个数为 a,倒数第二个为 b,只要 a-1,b+1 就好了。当然如果 a-1 = b+1 这个拆分也是不靠谱的这道题目就这样搞定了,其实没必要找所有的完全平方数,只要找小于 N 与 N 最接近的完全平方数就好了。
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    int hash[1010];
    int main()
    {
        for(int i=1;i<=1000;i++)
        hash[i]=i*i;
        int n,k;
        while(~scanf("%d%d",&n,&k))
        {
            int sign=0;
            int m=(int)sqrt(n*1.0);
            if(m*m==n)
            m--;
            for(int i=m;i>=0;i--)
            {
               int p=hash[m];
               int temp=n-p;
               int t=1;
               int xi=0;
               for(int j=1;j<k-1;j++)//开始构造k-1个数中的前k-2个
               {
                   if(t==temp)//与要去掉的那个数重合跳过
                   t++;
                   p-=t;
                   if(p<=t)
                   {
                       xi=1;
                       break;
                   }
                   t++;
               }
               if(xi==0)//判断第k-1个数是否符合
               {
                   if(p==temp)//与要去掉的那个数重合
                   {
                       p--;
                       t++;
                   }
                   if(p<t)//第k-1个数在前面k-2个数中要没出现过
                    ;
                   else
                   {
                       sign=1;
                   }
               }
            }
            if(sign)
            printf("YES\n");
            else
            printf("NO\n");
        }
        return 0;
    }
    


    你可能感兴趣的:(Algorithm)