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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值