Problem Description
Mo’s algorithm can solve some difficult data structure problems. Like this: You are given an array a1,a2,…,an 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 al,al+1,…,ar.
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:
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 al,al+1,…,ar 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(mn√).
In this task, you are given the length of the sequence n and m queries q1,q2,…,qm. Please write a program to rearrange these queries that cost(q1,q2)+cost(q2,q3)+⋯+cost(qm−1,qm) 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 li and ri(1≤li≤ri≤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
// 题意易猜得;;;一发过了。。。
题意:给你一个n长度的数组,给你m次查询机会,通过m次重新排序,使得m个的l,r差值最小,输出最小差值。
题解:全排列m个l,r,找出最小的差值,输出即可。m范围小,暴力即可。暴力排列所有情况
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=110;
int t,n,m,k;
struct node{
int l;
int r;
};
node f[maxn];
int a[11];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=m;i++)
a[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&f[i].l,&f[i].r);
}
int ans=0x3fffffff;
do{
int t=0;
for(int i=2;i<=m;i++)
{
t+=abs(f[a[i]].l-f[a[i-1]].l);
t+=abs(f[a[i]].r-f[a[i-1]].r);
}
ans=min(ans,t);
}while(next_permutation(a+1,a+m+1));
printf("%d\n",ans);
}
return 0;
}
Problem Description
There is an infinite integer sequence f1,f2,f3,…, where f1=1,f2=2,fi=fi−1+fi−2(i≥3).
You are given two positive integers n and k, your task is to check whether n can be split into k integers a1,a2,…,ak, where a1,a2,…,ak∈f and a1+a2+⋯+ak=n. Note that you can split n into same integers, for example, 10=5+5=f4+f4.
Input
The first line of the input contains an integer T(1≤T≤100000), denoting the number of test cases.
In each test case, there is one integer n(1≤n,k≤1018) in the first line.
Output
For each test case, print a single line. If it is possible to split n into k integers, print Yes, otherwise print No.
Sample Input
4
10 1
10 2
5 1
12 2
Sample Output
No
Yes
Yes
No
题意:一个数列f1=1,f2=2;fn = fn-1 + fn-2;问n可否由k个数构成,能则输出yes,不能输出no
//dfs剪枝没剪好容易TLE。TLE两发,罚时40min,呜呜~
题解:由斐波那契数列构成可以,发现后面的数可以由前面的数组成,则计算出1e18,范围内所有函数值(f88时将会>1e18)。则减去后面最大值,消耗一次k,将n刚刚好消耗完,k>=0时即可输出yes(>0也可输出yes因为后面的大数,可拆分为前面的小的数(观察推理即可发现))。特殊情况判断,n==k输出yes,n < k 输出no
代码:
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=110;
ll f[maxn];
ll t,n,m,k;
int main()
{
cin>>t;
f[1]=1;f[2]=2;
for(int i=3;i<=100;i++)
{
f[i]=f[i-1]+f[i-2];
}
while(t--)
{
cin>>n>>k;
if(n<k)
{
puts("No");
continue;
}
if(n==k)
{
puts("Yes");
continue;
}
while(n>0 && k>0)
{
for(int i=88;i>=1;i--)
{
if(n>=f[i] && k>0)
{
n-=f[i];
k--;
break;
}
}
}
if(n==0 && k>=0)
puts("Yes");
else
puts("No");
}
return 0;
}
C题:
目测bfs,最短路,priority_queue解决。待补题(还是太菜了啊!!!