A. Little Elephant and Problem
题意:给出一个数组,问是否是由一个已排序的数组经过交换至多一对数得到。
解法:将给定的数组排序后与元数组比较,若有多于两个位置不同则不是,否则将原数组两个位置的数字交换后比较是否与排序后数组相同。
B. Little Elephant and Array
题意:给出一个数组,问某个自区间内有多少个x出现了x次。
解法:对与大于n的数,直接忽略。两种做法:
1.类似于hdu4358http://blog.csdn.net/kksleric/article/details/7935277
2.考虑整个区间内出现过x次的值x最多有sqrt(n)个,因此逐一处理这样的元素,离线处理每个查询去子区间内有多少个此x,最后输出。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.TreeMap;
public class d {
int maxn = 100010;
StreamTokenizer in = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));
int nextInt() throws IOException {
in.nextToken();
return (int) in.nval;
}
int arr[] = new int[maxn],num[] = new int[maxn], sum[] = new int[maxn];
int left[] = new int[maxn], right[] = new int[maxn], ans[] = new int[maxn];
void run() throws IOException {
int n = nextInt();
int m = nextInt();
for (int i = 1; i <= n; i++) {
arr[i] = nextInt();
if (arr[i] > n)
arr[i] = 0;
num[arr[i]]++;
}
for (int i = 1; i <= m; i++) {
left[i] = nextInt();
right[i] = nextInt();
}
for (int i = 1; i <= n; i++)
if (arr[i] != 0 && num[arr[i]] >= arr[i]) {
num[arr[i]] = 0;
for (int j = 1; j <= n; j++) {
sum[j]=sum[j-1];
if(arr[j]==arr[i])
sum[j]++;
}
for(int j=1;j<=m;j++)
if(sum[right[j]]-sum[left[j]-1]==arr[i])
ans[j]++;
}
for(int i=1;i<=m;i++)
System.out.println(ans[i]);
}
public static void main(String[] args) throws IOException {
new d().run();
}
}
C. Little Elephant and Shifts
题意:给出ab两个排列,连个排列之间的距离定义为每个元素index距离差绝对值的最小值,问b排列左移1、2、3、4、5---n-1次后两排列的距离。
解法:由于距离的定义为绝对值的最小值,因此分负数和正数两种情况考虑,设每个元素的初始距离为x[i]则对于x[i]为负数的点,除当前第一个元素外每次移动都会减小,即仍为负数,第一个元素的距离移到追尾变为非负数;对于x[i]为非负数的点,移动x[i]+1次后变成负数;
因此开两个map分别维护负值x和正值x,当正负号方式改变时从一个map移到另一个map,为便于维护,我们插入的值都是相对大小,在去除最小值之后加上偏移(移动次数)得到当前最小距离。
import java.util.Scanner;
import java.util.TreeMap;
public class Shift220C {
class MAP {
TreeMap<Integer, Integer> mp = new TreeMap<Integer, Integer>();
void add(int k, int t) {
if (t == 0)
return;
if (mp.containsKey(k))
mp.put(k, t + mp.get(k));
else
mp.put(k, t);
}
void del(int k, int t) {
if (t == 0)
return;
if (!mp.containsKey(k))
return;
if (mp.get(k) == t)
mp.remove(k);
else
mp.put(k, mp.get(k) - t);
}
int getmin() {
if (mp.isEmpty())
return inf;
return mp.firstKey();
}
int getmax() {
if (mp.isEmpty())
return -inf;
return mp.lastKey();
}
}
int inf = 1 << 28, maxn = 100010;
MAP neg = new MAP(), pos = new MAP();
int pa[] = new int[maxn], b[] = new int[maxn];
int num[] = new int[maxn * 2], x[] = new int[maxn];
Scanner scan = new Scanner(System.in);
void run() {
int n = scan.nextInt();
for (int i = 1; i <= n; i++)
pa[scan.nextInt()] = i;
for (int i = 1; i <= n; i++) {
b[i] = scan.nextInt();
x[i] = i - pa[b[i]];
if (x[i] < 0)
neg.add(x[i], 1);
else {
num[x[i]]++;
pos.add(x[i], 1);
}
}
System.out.println(Math.min(-neg.getmax(), pos.getmin()));
for (int i = 1; i < n; i++) {
if (x[i] + 1 < i)
neg.del(x[i], 1);
else {
pos.del(x[i], 1);
num[x[i]]--;
}
int temp = n - pa[b[i]] + i;
pos.add(temp, 1);
num[temp]++;
pos.del(i - 1, num[i - 1]);
neg.add(i - 1, num[i - 1]);
System.out.println(Math.min(-neg.getmax() + i, pos.getmin() - i));
}
}
public static void main(String[] args) {
new Shift220C().run();
}
}
E. Little Elephant and Inversions
题意:how many pairs of integers l and r are there, such that 1 ≤ l < r ≤ n and sequence b = a1a2... alarar + 1... an has no more than k inversions.
解法:首先观察单调性,若<l,r>符合要求则<l+i,r+i>也符合要求,因此题目变为对于一个固定的r,找出最大的l使得满足要求。首先求出这个区间的逆数对数,然后使用two pointers,使得每个元素入队出队一次,同时使用树状数组维护每个元素构成的逆序对数,求出最大r后统计答案。(固定l需找最小的r貌似维护起相对麻烦),注意b要包含al和ar,统计时需要特判。
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
public class Inversions220E {
int maxn = 100010;
class IndexTree {
int ss[] = new int[maxn + 10];
int N = maxn;
int lowbit(int k) {
return (k & -k);
}
void inc(int i, int v) {
while (i <= N) {
ss[i] += v;
i += lowbit(i);
}
}
int get(int i) {
int res = 0;
while (i > 0) {
res += ss[i];
i -= lowbit(i);
}
return res;
}
}
IndexTree all = new IndexTree(), pre = new IndexTree(),
now = new IndexTree();
TreeMap<Integer, Integer> mp = new TreeMap<Integer, Integer>();
int arr[] = new int[maxn];
Scanner scan = new Scanner(System.in);
void run() {
int n = scan.nextInt();
long k = scan.nextLong();
long sum = 0, ans = 0;
for (int i = 1; i <= n; i++) {
arr[i] = scan.nextInt();
mp.put(arr[i], 0);
}
int cnt = 0;
Set<Integer> set = mp.keySet();
for (int i : set)
mp.put(i, ++cnt);
for (int i = 1; i <= n; i++) {
arr[i] = mp.get(arr[i]);
all.inc(arr[i], 1);
sum += i - all.get(arr[i]);
}
if(sum<=k)
{
ans=1l*n*(n-1)/2;
System.out.println(ans);
return;
}
int left = 1, right =1;
now.inc(arr[1],1);
long res=sum-all.get(arr[1]-1);
while (left <= n) {
while (right <=n && res> k) {
right++;
now.inc(arr[right], 1);
res-=left-1-pre.get(arr[right]);
res-=all.get(arr[right]-1)-now.get(arr[right]-1)-pre.get(arr[right]-1);
}
while (left<right) {
long temp = left - 1 - pre.get(arr[left]);
temp += all.get(arr[left] - 1) - pre.get(arr[left] - 1)-now.get(arr[left]-1);
if(res+temp > k)
break;
pre.inc(arr[left],1);
now.inc(arr[left],-1);
res+=temp;
left++;
}
if (res<=k&&left!=1&&right!=n)
ans += left-1;
if(right==n)
break;
right++;
now.inc(arr[right], 1);
res-=left-1-pre.get(arr[right]);
res-=all.get(arr[right]-1)-now.get(arr[right]-1)-pre.get(arr[right]-1);
}
System.out.println(ans);
}
public static void main(String[] args) {
new Inversions220E().run();
}
}