来来来 来个详细思路
传送门:题面链接
Description
Mo’s algorithm can solve some difficult data structure problems. Like this: You are given an array a_1,a_2,…,a_n and m queries. In each query, we want to get the mode number(the value that appears most often in a set of data) of subsequence a_l, a_{l + 1},…,a_r.
Maybe you want to solve it using segment tree or some other data structures. However, if you know the answer of [l, k] and [k + 1, r], you will find that it is very difficult to get the answer of [l, r].
Mo’s algorithm is an offline algorithm that can solve this problem efficiently.
First, we need a data structure that can do these operations:
Insert a number.
Delete a number.
Get the mode number.
It can be solved easily by a binary heap or a balanced binary search tree. We call this data structure DS.
On the other hand, if we only keep a_l,a_{l+1},…,a_r in DS, we can transform to [l’, r’] in |l-l’| + |r-r’| moves. So we need to find a good order to perform queries that the total number of moves is minimized.
It is very hard to find such excellent order. Mo’s algorithm just gives an order that the total number of moves is O(m * sqrt{n}).
In this task, you are given the length of the sequence n and m queries q_1,q_2,…,q_m. Please write a program to rearrange these queries that cost(q_1,q_2)+cost(q_2,q_3)+…+cost(q_{m-1},q_m) is minimized, where cost([l,r],[l’,r’])=|l-l’| + |r-r’|.
Input
The first line of the input contains an integer T(1 <= T <= 10), denoting the number of test cases.
In each test case, there are two integers n,m(1 <= n <= 100000, 2 <= m <= 10) in the first line, denoting the length of the sequence and the number of queries.
For the next m lines, each line contains two integers l_i and r_i (1 <= l_i <= r_i <= n), denoting a query.
Output
For each test case, print a single line containing an integer, denoting the minimum number of moves.
Sample Input
2
5 2
1 5
3 4
9 5
5 5
1 1
4 4
2 2
3 3
Sample Output
3
8
题意:给你十个点,或者可以理解为十对LR排成 一列,去计算权值最小,计算方法是
ans=min(∑ abs(Li-L(i-1))+abs(Ri-R(i-1)) ) 理解为相邻两个LR的 绝对值差 为最小
但是以上两个方法都WA了说明这个题目不可以贪,(或者我菜)
这里要用到一个STL库的函数(完全可以自己在写一个)
STL提供了两个用来计算排列组合关系的算法,分别是next_permutation和prev_permutation。首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b,c}。
这个序列有六个可能的排列组合:abc,acb,bac,bca,cab,cba。这些排列组合根据less-than操作符做字典顺序(lexicographical)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。
贴个源码:
template<calss BidrectionalIterator>
bool next_permutation(BidrectionalIterator first,BidrectionalIterator last)
{
if(first == lase) return false; /* 空区间 */
BidrectionalIterator i = first;
++i;
if(i == last) return false; /* 只有一个元素 */
i = last; /* i指向尾端 */
--i;
for(;;)
{
BidrectionalIterator ii = i;
--i;
/* 以上锁定一组(两个)相邻元素 */
if(*i < *ii) /* 如果前一个元素小于后一个元素 */
{
BidrectionalIterator j = last; /* 令j指向尾端 */
while(!(*i < *--j)); /* 由尾端往前找,直到遇到比*i大的元素 */
iter_swap(i,j); /* 交换i,j */
reverse(ii,last); /* 将ii之后的元素全部逆序重排 */
return true;
}
if(i == first) /* 进行至最前面了 */
{
reverse(first,last); /* 全部逆序重排 */
return false;
}
}
}
在C++ Reference中查看了一下next_permutation的函数声明:
#include
bool next_permutation( iterator start, iterator end );
The next_permutation() function attempts to transform the given range of elements [start,end) into the next lexicographically greater permutation of elements. If it succeeds, it returns true, otherwise, it returns false.
从说明中可以看到 next_permutation 的返回值是布尔类型。
然后我们只需要用这个函数为所欲为就好了:
#include
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn=100;
int n,m;
int ans,sum;
int l[maxn],r[maxn],a[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)scanf("%d%d",&l[i],&r[i]);
for(int i=0;i<m;i++)a[i]=i;
ans=-1;
do
{
sum=0;
for(int i=1;i<m;i++)
sum+=abs(l[a[i]]-l[a[i-1]])+abs(r[a[i]]-r[a[i-1]]);
if(ans==-1) ans=sum;
else ans=min(ans,sum);
}while(next_permutation(a,a+m));
printf("%d\n",ans);
}
return 0;
}