第二次参加USACO 本来打算2016-2017全勤的 January的好像忘记打了 听群里有人讨论才想起来
铂金组三题很有意思,都是两个排列的交叉对问题 我最后得分889/1000(真的菜)


T1.Why Did the Cow Cross the Road
题目大意:给出两个N个排列(N<=100,000),允许把其中一个排列循环移动任意位,a[i]表示i在第一个排列中的位置,b[i]表示第二个,定义交叉对(i,j)满足a[i]<a[j]且b[i]>b[j],求最少交叉对。
思路:数字大小没有影响,于是令第一个排列中第一个出现的编号为1,第二个出现的编号为2,于是变成最小化第二个排列的逆序对,一开始的逆序对可以O(nlogn)求出,然后考虑把当前第一个数移到最后,若这个数编号为x,明显多了n-x个逆序对,少了x-1个逆序对,就可以O(n)求出所有循环移动第二个排列的情况,然后我开心的交了,开心的WA了,后来才知道,自己忘记考虑移第一个的情况了(其实只要反过来再做一遍)。
得分:8/10(幸好数据大多是移第二个的?)

#include<cstdio>
#include<iostream>
using namespace std;
char B[1<<26],*S=B,C;int X;
inline int read()
{
    while((C=*S++)<'0'||C>'9');
    for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
    return X;
}
#define MN 100000
#define N 131072
int f[MN+5],a[MN+5],t[N*2];
void inc(int k){for(k+=N;k;k>>=1)++t[k];}
int query(int l,int r)
{
    int res=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)res+=t[l+1];
        if( r&1)res+=t[r-1];
    }
    return res;
}
int main()
{
    freopen("mincross.in","r",stdin);
    freopen("mincross.out","w",stdout);
    fread(B,1,1<<26,stdin);
    int n=read(),i;long long ans,cnt=0;
    for(i=1;i<=n;++i)f[read()]=i;
    for(i=1;i<=n;++i)cnt+=query(a[i]=f[read()],n),inc(a[i]);
    for(ans=cnt,i=1;i<n;++i)if((cnt+=n-(a[i]<<1)+1)<ans)ans=cnt;
    cout<<ans;
}
View Code

相关文章:

  • 2022-12-23
  • 2021-06-18
  • 2022-12-23
  • 2021-06-05
  • 2022-12-23
  • 2021-10-30
  • 2021-05-17
猜你喜欢
  • 2021-11-09
  • 2021-11-19
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-24
相关资源
相似解决方案