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.");
}
}