ZOJ 3768 Continuous Login(暴力或夹逼原理)

参考:

http://blog.csdn.net/zhuhuangjian/article/details/23036139

http://blog.csdn.net/mid_kkks/article/details/23034401


本题预处理之后,就是一个背包问题,但是容量10e9,不能用背包。最后是判断出最多选择3个数,暴力解决或利用夹逼原理。

夹逼原理:2个数时,利用夹逼原理,O(n)解决。三个数时,枚举第一个,后两个夹逼原理判断。

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;

int sn;
int sum[100000];
map<int, int>mp;
int n;

bool pd(int x)///夹逼原理判断2个数的和为x
{
    int lowi = 1, upi = upper_bound(sum, sum + sn, x) - sum - 1;
    while (lowi <= upi)
    {
        if (sum[lowi] + sum[upi] < x)
            lowi++;
        else if (sum[lowi] + sum[upi] > x)
            upi--;
        else
        {
            printf("%d %d", lowi, upi);
            return true;
        }
    }
    return false;
}

int main ()
{
    mp.clear();
    sn = 1;
    mp[1] = 1;
    sum[1] = 1;
    while (1)
    {
        if (sum[sn] > 123456789) break;
        sn++;
        sum[sn] = sum[sn - 1] + sn;
        mp[sum[sn]] = sn;
    }
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        if (mp.count(n))
        {
            printf("%d\n", mp[n]);
            continue;
        }
        if (pd(n))
        {
            puts(""); continue;
        }
        int upi = upper_bound(sum, sum + sn, n) - sum - 1;
        for (int i = 1; i <= upi; i++)
        {
            if (pd(n - sum[i]))
            {
                printf(" %d\n", i); break;
            }
        }
    }
    return 0;
}

暴力处理:3个数时,枚举前两个,判断第三个。同时可利用3个数的大小关系优化。1个数直接判断,2个数时枚举一个,判断第二个。

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int MAXN = 1000010;

int sn;
int sum[100000];
map<int, int>mp;
int n;

int main ()
{
    mp.clear();
    sn = 1;
    mp[1] = 1;
    sum[1] = 1;
    while (1)
    {
        if (sum[sn] > 123456789) break;
        sn++;
        sum[sn] = sum[sn - 1] + sn;
        mp[sum[sn]] = sn;
    }
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        if (mp.count(n))
        {
            printf("%d\n", mp[n]);
            continue;
        }
        int flg = 0;
        int upi = upper_bound(sum, sum + sn, n) - sum;
        for (int i = 1; i <= upi; i++)
        {
            if (mp.count(n - sum[i]))
            {
                printf("%d %d\n", i, mp[n - sum[i]]);
                flg = 1;
                break;
            }
        }
        if (flg) continue;
        flg = 1;
        for (int i = upi; i >= 1 && flg; i--)
//        for (int i = 1; i <= upi && flg; i++)
        {
            int x = n - sum[i];
            int upj = upper_bound(sum, sum + sn, x) - sum;
            for (int j = min(i, upj); j >= 1 && flg; j--)
//            for (int j = 1; j <= upj && flg; j++)
            {
                int y = x - sum[j];
                if (mp.count(y))
                {
                    printf("%d %d %d\n", i, j, mp[y]);
                    flg = 0;
                    break;
                }
            }
        }
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值