一共四道题
题目1 : 互补二元组
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定N个整数二元组(X1, Y1), (X2, Y2), … (XN, YN)。
请你计算其中有多少对二元组(Xi, Yi)和(Xj, Yj)满足Xi + Xj = Yi + Yj且i < j。
输入
第一行包含一个整数N。
以下N行每行两个整数Xi和Yi。
对于70%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000 -1000000 ≤ Xi, Yi ≤ 1000000
输出
一个整数表示答案。
样例输入
5
9 10
1 3
5 5
5 4
8 6
样例输出
2
最初看到这道题的时候没有认真审题,认为(1,2)(3,2)(3,2)这种情况只计数一次(应该记两次),想办法将配过对的数组删除,结果耽误了很长时间,后来先做的后面几题,快结束时返回来再直接按字面意思做,过了70%(LTE)。比赛结束后翻到了某大神简洁的代码,膜拜。这道题将给定的条件Xi + Xj = Yi + Yj稍微变换一下可得 (Xi -Yi)+ (Xj - Yj) = 0, 所以将输入的数对作差值存储起来即可。考虑到X、Y的取值范围,可用map直接查找。嗯,以上的都能想到。大神的方法妙在存储X-Y时,直接对Y-X做加操作,省去了重复遍历和查找,很巧妙。(注意X,Y的取值范围,LL)
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
typedef long long ll;
using namespace std;
map<ll, ll> res;
int main()
{
int N; cin >> N;
ll cnt = 0;
int x, y;
while(N--) {
cin >> x >> y;
cnt += res[x-y];
res[y-x]++;
}
cout << cnt << endl;
return 0;
}
题目2 : 寻找切线
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定平面上N个点P1=(X1, Y1), P2=(X2, Y2), … PN=(XN, YN)。
请你从中找到两个不同的点Pi和Pj满足:其他所有点都在Pi和Pj连线的同一侧(可以在连线上)。
如果有多组答案满足条件,你可以输出任意一组。
输入
第一行包含一个整数N。
以下N行每行包含两个整数Xi和Yi。
对于50%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000 0 ≤ Xi, Yi ≤ 1000000
输出
输出由一个空格隔开的两个整数i和j,注意1 ≤ i, j ≤ N且i ≠ j。
样例输入
6
0 10
7 0
8 8
10 18
15 13
20 4
样例输出
5 6
方法:一条直线由两点确定:先找到 x/y 坐标最大值(最小值也可以)作为第一个点,再计算其余点与该点的斜率,取绝对值最大的点作为第二个点。
#include<iostream>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
#include<cmath>
#include<sstream>
using namespace std;
int main()
{
int n; cin >> n;
int x[n], y[n];
int m = 0, q = 0;
for(int i=0; i<n; i++) {
cin >> x[i] >> y[i];
if(x[i]>x[m]) m = i;
}
float k = 0;
for(int i=0; i<n; i++)
{
if(i==m) continue;
if(x[i]==x[m]) {q = i; break;}
float k1 = abs(1.0*(y[i]-y[m])/(x[i]-x[m]));
if(k1 > k) { k = k1, q = i;}
}
if(m < q) cout << m+1 << ' ' << q+1 << endl;
else cout << q+1 << ' ' << m+1 << endl;
return 0;
}
题目3 : LR问题
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
给定两个字符串S和T,每个字符串都由’L’、’R’和’_’组成。例如:
R__LR_R_L
每一次操作,可以将S中的一个’R’与它右边相邻的’‘交换(前提是这个R右边相邻位置就是’‘);或者将S中的一个’L’与它左边相邻的’‘交换(前提是这个L左边相邻位置就是’‘)。
例如,先移动第一个L,再移动第二个R会得到:
R__LR_R_L -> R_L_R_R_L -> R_L__RR_L
请你计算最少经过几次操作可以将S变成T。
输入
第一行包含一个字符串S。
第二行包含一个字符串T。
对于30%的数据,1 ≤ |S| = |T| ≤ 20
对于100%的数据,1 ≤ |S| = |T| ≤ 100000
输出
输出一个整数代表最少操作次数。
如果不论如何S也不能变成T,输出-1。
样例输入
R__LR_R_L
R_L__RR_L
样例输出
2
总是把简单问题复杂化,竟然想用dp,做的题量还是太少了。参照某大神简洁优美的代码如下:
#include <iostream>
#include <vector>
using namespace std;
int main(){
string s, t; cin>>s>>t;
vector<int> ss, tt;
for(int i=0;i<int(s.size());i++) if(s[i] != '_') ss.push_back(i);
for(int i=0;i<int(t.size());i++) if(t[i] != '_') tt.push_back(i);
if(ss.size() != tt.size()) return cout<<-1<<endl, 0;
int ans = 0;
for(int i=0;i<(ss.size());i++){
int sx = ss[i], tx = tt[i];
if(s[sx] != t[tx]) return cout<<-1<<endl, 0;
if(s[sx] == 'L' && sx < tx) return cout<<-1<<endl, 0;
if(s[sx] == 'R' && sx > tx) return cout<<-1<<endl, 0;
ans += abs(sx - tx);
}
cout<<ans<<endl;
return 0;
}
题目4 : 推断大小关系
时间限制:20000ms
单点时限:2000ms
内存限制:256MB
描述
有N个整数A1, A2, … AN,现在我们知道M条关于这N个整数的信息。每条信息是:
Ai < Aj 或者 Ai = Aj
小Hi希望你能从第一条信息开始依次逐条处理这些信息。一旦能推断出A1和AN的大小关系就立即停止。
输出在处理第几条时第一次推断出A1和AN的关系。如果处理完全部M条信息还是不知道A1和AN的大小关系,输出-1。
保证M条信息是没有矛盾的。
输入
第一行包含两个整数N和M。
以下M行每行包含一条信息Ai < Aj 或者 Ai = Aj。
对于30%的数据,1 ≤ N ≤ 1000, 1 ≤ M ≤ 10000
对于100%的数据,1 ≤ N ≤ 100000, 1 ≤ N ≤ 1000000
输出
一个整数表示答案。
样例输入
5 8
A1 < A3
A3 < A2
A3 < A4
A5 < A2
A1 < A4
A1 < A2
A5 < A1
A5 < A3
样例输出
7
参考了某大神的答案,嗯,,看懂了。知识点:二分查找、dfs
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1e6 + 10;
int x[maxn], op[maxn], y[maxn];
int n, m;
int fa[maxn];
int Find(int x)
{
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
void Union(int x, int y)
{
x = Find(x), y = Find(y);
fa[x] = y;
}
int vis[maxn];
vector<int> G[maxn];
void dfs(int x)
{
for(int i = 0; i < G[x].size(); i++)
{
int to = G[x][i];
if(vis[to]) continue;
vis[to] = 1, dfs(to);
}
}
bool check(int mid)
{
for(int i = 1; i <= n; i++) fa[i] = i, G[i].clear();
for(int i = 1; i <= mid; i++)
if(op[i] == 0) Union(x[i], y[i]);
for(int i = 1; i <= mid; i++)
{
if(op[i] == 1) G[Find(x[i])].push_back(Find(y[i]));
if(op[i] == -1) G[Find(y[i])].push_back(Find(x[i]));
}
for(int i = 1; i <= n; i++) vis[i] = 0;
vis[Find(1)] = 1;
dfs(Find(1));
if(vis[Find(n)]) return true;
for(int i = 1; i <= n; i++) vis[i] = 0;
vis[Find(n)] = 1;
dfs(Find(n));
if(vis[Find(1)]) return true;
return false;
}
int id(char * s)
{
int l = strlen(s);
int ret = 0;
for(int i = 0; i < l; i++) ret = ret * 10 + (s[i] - '0');
return ret;
}
int main(void)
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++)
{
char a[11], b[11], c[11];
scanf("%s %s %s", a, b, c);
cout << a << ' ' << b << ' '<< c << endl;
x[i] = id(a + 1), y[i] = id(c +1);
cout << x[i] << ' ' << y[i] << endl;
if(b[0] == '>') op[i] = 1;
if(b[0] == '<') op[i] = -1;
}
if(!check(m)) puts("-1");
else
{
int l = 1, r = m;
while(l < r)
{
int mid = l + (r - l) / 2;
if(check(mid)) r = mid;
else l = mid +1;
}
printf("%d\n", r);
}
return 0;
}