解题思路:
求出最大的横坐标差和最大的纵坐标轴之差,取较大值作为正方形城市边长即可。
代码:
#include <iostream>
#include <cmath>
using namespace std;
const int INF=1e9+5;
int main()
{
int n;
while(cin >> n)
{
int min_x=INF, max_x=-INF, min_y=INF, max_y=-INF;
int x, y;
for(int i=0; i<n; i++)
{
cin >> x >> y;
if(x > max_x)
max_x = x;
if(y > max_y)
max_y = y;
if(x < min_x)
min_x = x;
if(y < min_y)
min_y = y;
}
//坐标取值范围[-1e9, 1e9],面积可能大于int范围。
long long tmp = max(max_x-min_x,max_y-min_y);
cout << tmp*tmp << endl;
}
return 0;
}
解题思路:
解法1:离线+树状数组。先把询问离线,并且按照右端点排序,然后从小区间开始,然后树状数组的含义就是指以当前r为结尾的前缀区间(除去后面出现过的元素)的元素种类数,简单点说,当计算到l , r区间,把l - r区间还没在树状数组上更新的值,更新一遍,在之前已经存在了的值先删掉再更新一遍,确保我确定的元素都是往r靠的。
解法2:主席树。
解法3:暴力求解。维护一个大小为m的数组,记录每个数的前缀出现次数,把l - r区间的每个数相减,再统计出现次数大于0的数字总数即为答案。(时间复杂度为Q*m,只适用于Q*m较小时;若此题m的范围改为1~1000,则超时。)
(在解法1和解法2中,m均用不上)
代码(解法1):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N = 2005;
const int M = 1000005;
struct node
{
int x, y, id;
}b[M];
int c[N], ans[M], a[N];
map<int, int >vis;
bool cmp(node a, node b)
{
return a.y<b.y;
}
int lowbit(int x)
{
return x & (-x);
}
void update(int x, int val,int n)
{
while (x <= n)
{
c[x] += val;
x += lowbit(x);
}
}
int sum(int x)
{
int s = 0;
while (x)
{
s += c[x];
x -= lowbit(x);
}
return s;
}
int main()
{
int n, m, k;
while (~scanf("%d%d", &n, &k))
{
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
scanf("%d", &m);
for (int i = 0; i<m; i++)
{
scanf("%d%d", &b[i].x, &b[i].y);
b[i].id = i;
}
cout<<endl;
sort(b, b + m, cmp);
for (int k = 0; k<m; k++)
{
cout<<b[k].x<<" "<<b[k].y<<endl;
}
cout<<endl;
int pre = 1;
memset(c, 0, sizeof(c));
vis.clear();
for (int i = 0; i<m; i++)
{
for (int j = pre; j <= b[i].y; j++)
{
if (vis.find(a[j]) == vis.end())
update(j, 1, n);
else
{
update(vis[a[j]], -1, n);
update(j, 1, n);
}
vis[a[j]] = j;
}
ans[b[i].id] = sum(b[i].y) - sum(b[i].x - 1);
pre = b[i].y + 1;
}
cout<<endl;
for (int i = 0; i<m; i++)
printf("%d\n", ans[i]);
}
return 0;
}
解题思路:
很明显这是最长公共子序列LCS.
但是由于数据太大,普通的O(n2)的做法肯定不行,我们要考虑一种更快的做法.把LCS
问题转换成LIS
问题,然后再利用LIS
的nlogn
解法来求出答案。
思路是这样的,首先假设有两个串,为a
和b
,比如:
a | 1 | 2 | 3 | 5 | 4 |
---|---|---|---|---|---|
b | 5 | 4 | 3 | 2 | 1 |
下标 | 1 | 2 | 3 | 4 | 5 |
我们找出a
中的每个数在b
中的下标。
1出现在5位置,2出现在4位置,3出现在3位置,5出现在1位置,4出现在2位置,那么就形成了一个新的串.
5 4 3 1 2
(注意:若a中的元素在b中当有多个位置(k1,k2,k3……)时,要降序排列(k1>k2>k3),这样求最长上升子序列的时候,可以保证从这些位置中只取出一个)
然后对新生成的串求出LIS
长度就是答案
注:LCS在最终的时间复杂度上不是严格的O(nlogn),不知均摊上是不是。
举个退化的例子:
如 a:666 b:66666
则新的序列为432143214321
长度变成了n*m ,最终时间复杂度O(n*m*(lognm)) > O(n*m)。
不过此题每个元素都不一样,则算法时间复杂度O(nlogn)
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 50005;
int a[MAXN], lis[MAXN * 20], d[MAXN * 20];
vector<int> pos[MAXN];
int main()
{
int n;
while(~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
int b;
for (int i = 1; i <= n; i++)
{
scanf("%d", &b);
pos[b].push_back(i);
}
int len_lis = 1;
for (int i = 0; i <= n; i++)
for (int k = pos[a[i]].size() - 1; k >= 0; k--)
lis[len_lis++] = pos[a[i]][k];
d[1] = lis[1];
int max_len_lcs = 1;
for (int i = 2; i <= len_lis; i++)
{
if (lis[i] > d[max_len_lcs])
d[++max_len_lcs] = lis[i];
else
{
int pos_greater_than_lis_i = lower_bound(d, d + max_len_lcs, lis[i]) - d;
d[pos_greater_than_lis_i] = lis[i];
}
}
printf("%d\n", max_len_lcs);
}
return 0;
}