ACM-BestCoder Round #32

A-PM2.5

题意:
先按两次数据之差由大到小排序,若差相等则按第二次数据由小到大排序,若第二次数据还相等则按城市数据的输入的先后顺序排序。
分析:
由于排序规则有多个,所以搞个结构体按照规则排序就ok了。但是需要注意的是,当数据相等时,排完序后的顺序不一定是输入顺序,所以按输入序号排序还是需要的。
源代码:
#include <cstdio>
#include <algorithm>

using namespace std;

struct Data
{
    int first;
    int second;
    int id;
    bool operator < (const Data &other) const
    {
        if(first-second
           != other.first-other.second)
        {
            return first-second
             > other.first-other.second;
        }
        if(second != other.second)
        {
            return second < other.second;
        }
        return id < other.id;
    }
}data[105];

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; ++i)
        {
            scanf("%d%d",
                  &data[i].first, &data[i].second);
            data[i].id = i;
        }
        sort(data, data+n);
        for(int i=0; i<n; ++i)
        {
            printf(i?" %d":"%d", data[i].id);
        }
        putchar('\n');
    }

    return 0;
}

B-Negative and Positive (NP)

题意:问是否存在i、j,使得给出的k值等于那个关于i、j的表达式的值。
分析:如果直接枚举i、j,那么复杂度将是o(n^3);由于表达式是求和,所以想到可以先计算前缀和,那么复杂度是o(n^2);但是前面超时,所以考虑动态维护和,为了方便,假设sum[i]代后i项和(前缀和类似),那么如果要k = sum[i,j]成立的话,考虑奇偶,等价于k = sum[i]-sum[j]或k = -(sum[i]-sum[j])成立,因为a0为正或为负,然后从后往前枚举i,因为这样当在计算sum[i]时sum[j]是已经计算过了的,那么就只需查询sum[i]-k或sum[i]+k存在没,其实就是看有没有计算过的sum[j]和这次的sum[i]组合满足前面的等式,如果有则存在满足条件的i、j,否则继续枚举,同时将sum[i]保存,这样复杂度为o(n),至于保存数据的方法,要支持快速增加和查询元素,可以使用set或hash。
源代码:
1、使用set
#include <cstdio>
#include <set>

#define LL __int64
#define MAX 10000100

std::set <LL> st;
int data[MAX];
int n, k;

// 快速输入
void FaRead(int &x)
{
    int f=1;
    char ch=getchar();
    x = 0;
    while(ch<'0' || ch>'9')
    {
        if(ch=='-')
        {
            f  = -1;
        }
        ch = getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x  = x*10 + ch - '0';
        ch = getchar();
    }
    x *= f;
}

// c++ set集合实现
int solve()
{
    st.clear();
    LL sum = 0;
    st.insert(0);
    for(int i=n, t=1; i>=1; --i, t^=1)
    {
        // 注意奇、偶,后缀和将是+-+-+或-+-+-的形式
        if(t)
        {
            sum += data[i];
            if (st.find(sum-k) != st.end())
            {
                return 1;
            }
        }
        else
        {
            sum -= data[i];
            if(st.find(k+sum) != st.end())
            {
                return 1;
            }
         }
        st.insert(sum);
    }
    return 0;
}

int main ()
{
    int t, cas=0;
    scanf("%d", &t);
    while(t--)
    {
        FaRead(n);
        FaRead(k);
        for(int i=1; i<=n; ++i)
        {
            FaRead(data[i]);
        }
        printf("Case #%d: %s\n", ++cas,
               solve()?"Yes.":"No.");
    }
}
2、使用hash表
#include <cstdio>
#include <cstring>

#define LL __int64
#define MAX 10000100

const LL MOD = 1000007;
int data[MAX];
int n, k;

// 哈希表实现
struct HashTable
{
    struct Edge
    {
        LL num;
        int next;
    };

    Edge edge[2*MAX];
    int countedge;
    int head[MOD+100];

    void init()
    {
        memset(head, -1, sizeof(head));
        countedge = 0;
    }

    void insert(LL num)
    {
        int start = num%MOD;
        edge[countedge].next = head[start];
        edge[countedge].num  = num;
        head[start] = countedge;
        countedge++;
    }

    int find(LL num)
    {
        int start = num%MOD;
        int ind;
        for(ind=head[start]; ind!=-1; ind=edge[ind].next)
        {
            if(edge[ind].num == num)
            {
                break;
            }
        }
        return ind;
    }
}HT;

// 快速输入
void FaRead(int &x)
{
    int f=1;
    char ch=getchar();
    x = 0;
    while(ch<'0' || ch>'9')
    {
        if(ch == '-')
        {
            f  = -1;
        }
        ch = getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x  = x*10 + ch - '0';
        ch = getchar();
    }
    x *= f;
}

// c++ set集合实现
int solve()
{
    HT.init();
    LL sum = 0;
    HT.insert(0);
    for(int i=n, t=1; i>=1; --i, t^=1)
    {
        // 注意奇、偶,后缀和将是+-+-+或-+-+-的形式
        if(t)
        {
            sum += data[i];
            if (HT.find(sum-k) != -1)
            {
                return 1;
            }
        }
        else
        {
            sum -= data[i];
            if(HT.find(k+sum) != -1)
            {
                return 1;
            }
         }
        HT.insert(sum);
    }
    return 0;
}

int main()
{
    int t, cas=0;
    scanf("%d", &t);
    while(t--)
    {
        FaRead(n);
        FaRead(k);
        for(int i=1; i<=n; ++i)
        {
            FaRead(data[i]);
        }
        printf("Case #%d: %s\n", ++cas,
               solve()?"Yes.":"No.");
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值