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();
}
}