hdu 5143 NPY and arithmetic progression

24 篇文章 0 订阅
13 篇文章 0 订阅

喜欢acm,因为有挑战,很纯粹,付出了便会有收获。

题意:有a个1,b个2,c个3,d个4,问能否不重不漏的划分成一些长度大于等于3的等差数列(一个数列可以

出现多次)?

  今天开始训练用科学的方法来解题:

首先注意到这是一个对称的数列,a,b,c,d,所以可以分类从两方面着手问题:1.从两边开始着手,2.从中间着手

注意到如果想满足成立的条件必须要把使b == c,而两边着手问题没有太多的条件可以使用。

所以,我们从中间开始思考,首先发现必须使b == c && max(a,d) <= b && b <= a + d,如果能达到上述条件就能

所有元素不重不漏的拿光(极限情况,如果b == a + d,使a,b,c 和 b,c,d分别为等差数列,如果a == b == c == d

则a,b,c,d为等差数列)。

所以核心思路就是先枚举中间的情况,再枚举两边的情况,再注意边界处理便可以了


#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define check(i) (i != 1 && i != 2)
#define done(a,b,c,d) (b == c && max(a,d) <= b && b <= a + d)
inline bool _check_(int a,int b,int c,int d)
{
    for(int i = max(a - b,0);i <= a && (a - i) + d >= b;i++)
        for(int j = d - b;j <= d && (a - i) + (d - j) >= b;j++)
            if(check(i) && check(j) && done(a - i,b,c,d - j))
                return true;
    return false;
}
inline bool run(int a,int b,int c,int d)
{
    if(done(a,b,c,d))return true;
    if(a > 2 && b > 2 && c > 2 && d > 2)return true;
    if(b > c)swap(b,c);
    if(a > d)swap(a,d);
    for(int i = max(b - (a + d),0);i <= b;i++)
        if(check(i) && check(c - b + i))
            if(done(a,b - i,b - i,d) || _check_(a,b - i,b - i,d))
                return true;
    return false;
}
int main()
{
    int _,a,b,c,d;
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        bool ans = run(a,b,c,d);
        if(ans)puts("Yes");
        else puts("No");
    }
}


看到bestCoder提供了另一种方法比较容易编写

如果把所有形如123,123,123看成是三个常数列111,222,333。那么123,234,1234,各自出现的情况只能是0,1,2次

对123,234,1234出现的次数进行枚举,剩下的均当作常数列验证是否可行



#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define FOR(i) for(int i = 0;i <= 2;i++)
#define test(i) (i != 1 && i != 2 && i >= 0)
#define MAXN 30
int cnt = 0;
struct Node
{
    int a,b,c,d;
}node[MAXN];
void run()
{
    FOR(i)FOR(j)FOR(k)
    {
        node[cnt].a = i + j;
        node[cnt].b = i + j + k;
        node[cnt].c = i + j + k;
        node[cnt++].d = i + k;
    }
}
bool check(int a,int b,int c,int d)
{
    for(int i = 0;i < cnt;i++)
        if(test(a - node[i].a) && test(b - node[i].b) && test(c - node[i].c) && test(d - node[i].d))
            return true;
    return false;
}
int main()
{
    int _,a,b,c,d;
    run();
    scanf("%d",&_);
    while(_--)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
        bool ans = check(a,b,c,d);
        if(ans)puts("Yes");
        else puts("No");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值