HDU 1394
题意:第一个数可以放到最后一个后面,在随意多少个这样的操作或者不操作的情况下,问逆序列最少有多少个。
模拟一下这个操作,由于这道题只有0~N-1,所以就更加方便了。
对于第一个数A[i],比A[i]小的数一定在后面,所以以A[i]为前的逆序列有A[i](从0开始的),放到后面之后,比A[i]大的有n-1-A[i]个,也就是多出了这么些的序列,总共变化位-A[i]+n-1-A[i]
线段树跑一下一开始的逆序列即可。一开始线段树上都是0,每放进去一个赋值为1,代表出现了这个。(按顺序来的后面的发现比他大的已经出现一定是出现在他之前的因为顺序输入)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 100100;
const int INF=0x7fffffff;
using namespace std;
int lazy[maxn<<2];
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];
void PushUp(int rt) { //由左孩子、右孩子向上更新父节点
SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);
MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}
void PushDown(int rt,int m) { //向下更新
if (lazy[rt]) { //懒惰标记
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];
SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];
MAX[rt<<1]=MAX[rt<<1|1]=lazy[rt];
MIN[rt<<1]=MIN[rt<<1|1]=lazy[rt];
lazy[rt] = 0;
}
}
//所有的l,r,rt 带入1,n,1
void build(int l,int r,int rt) { //初始化建树
lazy[rt] = 0;
if (l== r) {
SUM[rt]=MAX[rt]=MIN[rt]=0; //初始化为0的建树
/*scanf("%d",&SUM[rt]); //边读入边建树的方法
MAX[rt]=MIN[rt]=SUM[rt];
*/
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int v,int l,int r,int rt) { //将L~R区间的值置为v
//if(L>l||R>r) return;
if (L <= l && r <= R) {
lazy[rt] = v;
SUM[rt] = v * (r - l + 1);
MIN[rt] = v;
MAX[rt] = v;
//printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);
return ;
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , v , lson);
if (R > m) update(L , R , v , rson);
PushUp(rt);
}
int querySUM(int L,int R,int l,int r,int rt) { //求区间L~R的和
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return SUM[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += querySUM(L , R , lson);
if (m < R) ret += querySUM(L , R , rson);
return ret;
}
int queryMIN(int L,int R,int l,int r,int rt) { //求区间L~R的最小值
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return MIN[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = INF;
if (L <= m) ret = min(ret, queryMIN(L , R , lson));
if (m < R) ret = min(ret,queryMIN(L , R , rson));
return ret;
}
int queryMAX(int L,int R,int l,int r,int rt) { //求区间L~R的最大值
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return MAX[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = -INF;
if (L <= m) ret = max(ret, queryMAX(L , R , lson));
if (m < R) ret = max(ret,queryMAX(L , R , rson));
return ret;
}
int A[5000];
int main()
{
int n;
int k;
int sum;
while(cin>>n)
{
k=0;
build(1,n,1);
for(int i=1;i<=n;i++)
cin>>A[i];
for(int i=1;i<=n;i++)
{
k+=querySUM(A[i]+1+1,n,1,n,1);
update(A[i]+1,A[i]+1,1,1,n,1);
}
sum=k;
for(int i=1;i<=n;i++)
{
k=k-A[i]+n-1-A[i];
sum=min(sum,k);
}
cout<<sum<<endl;
}
}
就算数据不是0-N,离散化一下就好了
int A[1001000];
struct nod
{
int data;
int ind;
} B[1001000];
int cmp(nod A,nod B)
{
return A.data<B.data?true:false;
}
map < int,int>map0;
int main()
{
int n;
int k=0;
int sum;
cin>>n;
build(1,n,1);
for(int i=1;i<=n;i++)
{
cin>>A[i];
B[i].data=A[i];
B[i].ind=i;
}
sort(B+1,B+1+n,cmp);
int d=0;
for(int i=1;i<=n;i++)
{
if(map0[B[i].data]>0)
{
A[B[i].ind]=d;
}
else
{
d++;
A[B[i].ind]=d;
}
map0[B[i].data]++;
}//离散化
}
归并排序:
树状数组:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
int sum[200050];
int A[200050];
int n;
int lowbit(int x)
{
return x&(-x);
} //返回最小的值
void update(int pos,int val)//单点修改
{
while(pos<=n)
{
sum[pos]+=val;
pos+=lowbit(pos);
}
}//维护的是前缀和
int query(int pos)
{
if(pos==0)return 0;
int s=0;
while(pos)
{
s+=sum[pos];
pos-=lowbit(pos);
}
return s;
}//就算是前面的更新,也只是把需要用到的更新了,求区间和的时候需要按1的位置加起来。
int main()
{
while(cin>>n)
{
int pre;
int tot=0;
memset(sum,0,sizeof(sum));
for(int k=1;k<=n;k++)
{
scanf("%d",&pre);
A[k]=pre;
update(pre+1,1);
tot+=query(n)-query(pre+1);
}
int k=tot;
for(int i=1;i<=n;i++)
{
k=k-A[i]+n-1-A[i];
tot=min(tot,k);
}
// cout<<k<<endl;
cout<<tot<<endl;
}
}
UESTC 2018 Summer Training #4 Div.2 的E题
重头戏。
Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants her partner to be clever too (although he's not)! Parmida has prepared the following test problem for Pashmak.
There is a sequence a that consists of n integers a1, a2, ..., an. Let's denote f(l, r, x) the number of indices k such that: l ≤ k ≤ r and ak = x. His task is to calculate the number of pairs of indicies i, j (1 ≤ i < j ≤ n) such that f(1, i, ai) > f(j, n, aj).
Help Pashmak with the test.
Input
The first line of the input contains an integer n (1 ≤ n ≤ 106). The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 109).
Output
Print a single integer — the answer to the problem.
Examples
Input
7
1 2 1 1 2 2 1
Output
8
Input
3
1 1 1
Output
1
Input
5
1 2 3 4 5
Output
0
这道题和上面那道题类似。离散化了一下下。(但是发现不离散化照样能过...但还是写一下:这题离散化要求度不高数据还是太小,有点卡MAP,我写的第一遍读错题所以疯狂MAP然后就T了)MAP是logN的尽量不要反复调用。
主要用C【】记录一下1`i之前出现的次数,map1[a[I]]是总次数,相减加1才是j~n的次数,查找比这个次数打得,从次数+1到N查找即可。和上面那题求逆序列一样。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include<map>
#define max(a,b) (a>b)?a:b
#define min(a,b) (a>b)?b:a
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 1001000;
const int INF=0x7fffffff;
using namespace std;
int lazy[maxn<<2];
int MAX[maxn<<2];
int MIN[maxn<<2];
int SUM[maxn<<2];
void PushUp(int rt) { //由左孩子、右孩子向上更新父节点
SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
MAX[rt] = max(MAX[rt<<1],MAX[rt<<1|1]);
MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}
void PushDown(int rt,int m) { //向下更新
if (lazy[rt]) { //懒惰标记
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
SUM[rt<<1] = (m - (m >> 1)) * lazy[rt];
SUM[rt<<1|1] = ((m >> 1)) * lazy[rt];
MAX[rt<<1]=MAX[rt<<1|1]=lazy[rt];
MIN[rt<<1]=MIN[rt<<1|1]=lazy[rt];
lazy[rt] = 0;
}
}
//所有的l,r,rt 带入1,n,1
void build(int l,int r,int rt) { //初始化建树
lazy[rt] = 0;
if (l== r) {
SUM[rt]=MAX[rt]=MIN[rt]=0; //初始化为0的建树
/*scanf("%d",&SUM[rt]); //边读入边建树的方法
MAX[rt]=MIN[rt]=SUM[rt];
*/
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int v,int l,int r,int rt) { //将L~R区间的值置为v
//if(L>l||R>r) return;
if (L <= l && r <= R) {
lazy[rt] = v;
SUM[rt] = v * (r - l + 1);
MIN[rt] = v;
MAX[rt] = v;
//printf("%d %d %d %d %d\n", rt, sum[rt], c, l, r);
return ;
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
if (L <= m) update(L , R , v , lson);
if (R > m) update(L , R , v , rson);
PushUp(rt);
}
int querySUM(int L,int R,int l,int r,int rt) { //求区间L~R的和
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return SUM[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += querySUM(L , R , lson);
if (m < R) ret += querySUM(L , R , rson);
return ret;
}
int queryMIN(int L,int R,int l,int r,int rt) { //求区间L~R的最小值
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return MIN[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = INF;
if (L <= m) ret = min(ret, queryMIN(L , R , lson));
if (m < R) ret = min(ret,queryMIN(L , R , rson));
return ret;
}
int queryMAX(int L,int R,int l,int r,int rt) { //求区间L~R的最大值
if (L <= l && r <= R) {
//printf("%d\n", sum[rt]);
return MAX[rt];
}
PushDown(rt , r - l + 1);
int m = (l + r) >> 1;
int ret = -INF;
if (L <= m) ret = max(ret, queryMAX(L , R , lson));
if (m < R) ret = max(ret,queryMAX(L , R , rson));
return ret;
}
int A[1001000];
int C[1001000];
struct nod
{
int data;
int ind;
} B[1001000];
int cmp(nod A,nod B)
{
return A.data<B.data?true:false;
}
map < int,int>map0;
map < int,int>map1;
int D[1001000];
int E[1001000];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
}
for(int i=1;i<=n;i++)
{
map1[A[i]]++;
C[i]=map1[A[i]];
}
build(1,n,1);
long long sum=0;
int pre;
memset(D,0,sizeof(D));
for(int i=1;i<=n;i++)
{
sum+=querySUM(map1[A[i]]-C[i]+1+1,n,1,n,1);
pre=querySUM(C[i],C[i],1,n,1);
update(C[i],C[i],++pre,1,n,1);
}
cout<<sum<<endl;
}