#P00573. 冲锋&&#P00574. 冲锋2

一,#P00573. 冲锋

Description

J将军正在组织他手下的士兵攻击敌人。J将军发现不能让所有的士兵一次性压上。而是应该分成若干个梯队,这些梯队的人数最好形成连续的正整数。例如当他手下有15个士兵时。他应该有以下几种分法

15=1+2+3+4+5

15=4+5+6

15=7+8

但他同时也发现如果手上只有4个士兵时,则无法进行这样的分解。 现在给出J将军手下的士兵人数N,请问他能不能进行分解

Format

Input

一行给出数字N

Output

如果能分解就输出“YES”,否则输出"NO"

Samples

输入数据 1

15

Copy

输出数据 1

YES

二,题目意思分析

意思就是给你一个数字,请问它能否成为一个公差为1的等差数列之和。


三,思路 

结论:2的次方一定不可以,其他的都可以。

有两种可能:

1.如果n是奇数   那么是绝对能进行分解的,因为奇数可以看成是2*n+1,也可以看成是n+(n+1)

2.如果n是偶数   如10,10可以分为2*5.其中5为奇数,2*5的乘法说明了10可以分为两组数,每组和为5,即2和3,1和4;又如98,98=2*49=2*7*7=14*7,提示其可分为4组,每组平均值为14,即11,12,13,14,15,16,17,以此类推,只要一个不能写成若干奇数与偶数相乘之积的形式的数就不可以进行分解,也就是能写成若干个2相乘的形式的数就不可以


四,代码

#include <bits/stdc++.h>
using namespace std;
int n,t,g;
int main()
{
  cin>>n;
  while(n % 2 == 0) n /= 2;
  if(n == 1) cout<<"NO";
  else cout<<"YES";
  return 0;
}







 一, #P00574. 冲锋2

Description

J将军正在组织他手下的士兵攻击敌人。J将军发现不能让所有的士兵一次性压上。而是应该分成若干个梯队,这些梯队的人数最好形成连续的正整数。例如当他手下有15个士兵时。他应该有以下几种分法

15=1+2+3+4+5

15=4+5+6

15=7+8

但他同时也发现如果手上只有4个士兵时,则无法进行这样的分解。 现在给出J将军手下的士兵人数N,请问他能不能进行分解,如果可以则输出分解的方案

Format

Input

一个正整数

Output

输出符合题目描述的全部正整数序列 每行一个序列,每个序列都从该序列的最小正整数开始、以从小到大的顺序打印。 如果结果有多个序列,按各序列的最小正整数的大小从小到大打印各序列。 此外,序列不允许重复,序列内的整数后面有一个空格。如果没有符合要求的序列,输出 "NONE"。

Samples

输入数据 1

15


Copy

输出数据 1

1 2 3 4 5 
4 5 6 
7 8

 二,分析题意

可以看出,这道题就是上一题的举一反三,因为它还让我们输出所有方案。


三,思路

首先,无解的情况判断和上题一样

因为等差数列求和公式为(头+尾) *个数/ 2,答案为输入的数n
那么相当于知道n,求有没有头,尾,个数可以满足上述公式。
但枚举头,尾,个数求是否等于会超时
所以在这里因为该数列公差一定为1, 所以尾=头+个数-1
代入公式,得到(2*头+个数-1)*个数/ 2=n
但是如果枚举头和个数时间复杂度为O(n^2),仍会超时,所以要继续推
我们在这里是已知n的,那么可否通过n和个数推出头呢?
将前面的公式解括号变成(2*头*个数+个数^2一个数) / 2=n
再变成头*个数+ (个数^2/2-个数/ 2)=n
头*个数=n-个数^2/ 2+个数/ 2
头= (n-个数^2/2 +个数/2) /个数
(n-个数^2/ 2 +个数/ 2)/个数=头
那么,我们就只需枚举个数,就可求出头,也就可以求出等差数列的和以及判断和是否为n等操作了。


四,代码

#include <bits/stdc++.h>
using namespace std;
int n,t,op;
vector<int>vec[100001];
int main()
{
  cin>>t;
  n = t;
  while(t % 2 == 0) t /= 2;
  if(t == 1) cout<<"NONE";//无解
  for(int g = 1; g <= n; g++)//枚举等差数列数字个数
  {
    t = (n - (g * g) / 2 + g / 2) / g;//求出头
    int w = t + g - 1;//求出尾
    if(t == 0 || t >= n) continue;//头不能为0,也不能>=n
    int p = (t + w) * g / 2;//求出等差数列的和
    if(p == n)//如果等差数列的和等于n,说明找到了一个解
    {
      for(int k = t; k <= t + g - 1; k++) vec[op].push_back(k);//存进解数组中
      op++;
    }
    else if(p > n) break;//剪枝
  }
  for(int i = op - 1; i >= 0; i--)//输出结果
  {
    for(int j = 0; j < vec[i].size(); j++)
      cout<<vec[i][j]<<" ";
    cout<<endl;
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值