• usaco 2017 February platinum


    1.一条路,两边都是一个1到n的全排列,可以把其中一个全排列的起始位置改变(比如123可以变成231或者312)

    然后把相同的数连起来,求小交叉数。

    先算一下交叉数,然后直接一步步移动,O1更新一下状态就可以了。注意两边都要算过去。

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 131072
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int T[N*2+5];
    int n;
    int s2[N];
    int s[N],pos[N];
    int pos2[N];
    int up[N],down[N];
    ll tot=0,tot2;
    ll minn;
    
    void renew(int x,int ad)
    {
        T[x+=N]=ad;
        for(x>>=1;x;x>>=1)
        {
            T[x]=T[x<<1]+T[(x<<1)+1];
        }
    }
    
    int query(int l,int r)
    {
        int sum=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) sum+=T[l+1];
            if( r&1) sum+=T[r-1];
        }
        return sum;
    }
    
    int main()
    {
        freopen("mincross.in","r",stdin);
        freopen("mincross.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
        {
            s[i]=read();
            pos2[s[i]]=i;
        }
        for(int i=1;i<=n;i++)
        {
            s2[i]=read();
            pos[s2[i]]=i;
        }
        for(int i=1;i<=n;i++)
        {
            up[i]=query(1,pos[s[i]]);
            down[i]=i-1-up[i];
            renew(pos[s[i]],1);
            tot+=(ll)down[i];
        }minn=tot2=tot;
        for(int i=n;i>1;i--)
        {
            tot-=n-pos[s[i]];tot+=pos[s[i]]-1;
            tot2-=n-pos2[s2[i]];tot2+=pos2[s2[i]]-1;
            minn=min(minn,min(tot,tot2));
        }
        cout<<minn;
        return 0;
    }

    2.有一条路,路两边都有一个随意顺序的1-n n个点。如果|a-b|<=4 那么这两个点可以连边。

    现在要让所有边边两两不交叉,求最多可以连多少边。

    有一道金组的一样的题目 n<=1000  直接dp即可

    这道题则加大了数据 n<=100000 

    所以优化一下,边最多9*n条,我们可以在左边从上到下做,在右边用一个线段树第i个位置表示只和1-i部分的点连线,最多可以连几条。

    那么每次用每条边更新一下答案就行了。复杂度nlogn*9

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define N 131072
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int n;
    int s[N],pos[N];
    int f[N];
    int T[N*2+5];
    
    void renew(int x,int ad)
    {
        T[x+=N]=ad;
        for(x>>=1;x;x>>=1)
        {
            T[x]=max(T[x<<1],T[(x<<1)+1]);
        }
    }
    
    int query(int l,int r)
    {
        int sum=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) sum=max(sum,T[l+1]);
            if( r&1) sum=max(sum,T[r-1]);
        }
        return sum;
    }
    
    int main()
    {
        freopen("nocross.in","r",stdin);
        freopen("nocross.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
        {
            s[i]=read();
        }
        for(int i=1;i<=n;i++)
        {
            int x=read();pos[x]=i;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=max(1,s[i]-4);j<=min(n,s[i]+4);j++)
            {
                f[pos[j]]=max(f[pos[j]],query(1,pos[j]-1)+1);
            }
            for(int j=max(1,s[i]-4);j<=min(n,s[i]+4);j++)
                 renew(pos[j],f[pos[j]]);
        }
        printf("%d
    ",query(1,n));
        return 0;
    }

    3.还是这样一条路,路两旁还是1到n的全排列,这时候给定k 只有|a-b|<=k a和b才是友善的。

    现在左右两边相同数字连边,求不友善的交叉的个数。n,k<=100000

    查交叉个数可以用一个权值线段树在nlogn内查,这道题也可以用一个二维线段树做....

    但是这显然太复杂了,我们考虑用cdq分治来解决这个问题。

    基本思路:按照1-n的顺序,插入点,每次插入一个点m,就查一下m+k+1的答案。

    所以把询问和插入节点按照时间戳进行cdq分治

    每次计算答案时,将左边的插入操作和右边的查询操作按照左边的出现顺序排序,并且用线段树的做法查询答案就行了。

    所以正着做一次反着做一次....复杂度nlog^2n

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define N 131072
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    } 
    
    int n,k;
    
    ll ans=0;
    int T[N*2+5];
    
    struct cow{
        int x,y,k;
    }s[100005],q[200005],a[200005];
    
    bool cmp(cow x,cow y){return x.x<y.x||(x.x==y.x&&x.k<y.k);}
    
    void renew(int x,int ad)
    {
        //cout<<"renew"<<x<<" "<<ad<<endl;
        T[x+=N]=ad;
        for(x>>=1;x;x>>=1) T[x]=T[x<<1]+T[(x<<1)+1];
    }
    
    void query(int l,int r)
    {
    //    cout<<"query"<<l<<" "<<r<<endl;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1) ans+=T[l+1];
            if( r&1) ans+=T[r-1];    
        }
    }
    
    void solve(int l,int r)
    {
        int mid=(l+r)/2,m=0;
        for(int i=l;i<=mid;i++)   if(!q[i].k)a[++m]=q[i];
        for(int i=mid+1;i<=r;i++) if( q[i].k)a[++m]=q[i];
        sort(a+1,a+m+1,cmp);
        for(int i=1;i<=m;i++)
        if(a[i].k) query(a[i].y,n);    
        else renew(a[i].y,1);
        for(int i=1;i<=m;i++) if(!a[i].k) renew(a[i].y,0);
    }
    
    void work(int l,int r)
    {
        if(l<r)
        {
            int mid=(l+r)/2;
            work(l,mid);work(mid+1,r);    
            solve(l,r);
        }
    }
    
    int main()
    {
        freopen("friendcross.in","r",stdin);
        freopen("friendcross.out","w",stdout);
        n=read();k=read();
        for(int i=1;i<=n;i++)
            s[read()].x=i;
        for(int i=1;i<=n;i++)
            s[read()].y=i;
        for(int i=1;i<=n-k-1;i++)
            q[(i<<1)-1]=s[i],q[i<<1]=s[i+k+1];    
        for(int i=1;i<=n-k+1;i++) q[i<<1].k=1;
        work(1,(n-k-1)<<1);
        for(int i=n,j=1;i>=k+2;--i,++j)
            q[(j<<1)-1]=s[i],q[j<<1]=s[i-k-1];    
        for(int i=1;i<=n-k+1;i++) q[i<<1].k=1;
        work(1,(n-k-1)<<1);
        cout<<ans;
        return 0;
    }

     感想:怎么都有线段树。。???

    FallDream代表秋之国向您问好! 欢迎您来我的博客www.cnblogs.com/FallDream
  • 相关阅读:
    linux LVM详解
    Mysql SQL优化系列之——执行计划连接方式浅释
    Vue SSR常见问题、异常处理以及优化方案
    vue组件生命周期详解
    axios全局设置url公共请求头
    WebView中JS调用Android Method 遇到的坑整理
    node.js项目多环境配置
    用vue构建多页面应用
    前端系列-移动端开发踩过的一些坑
    Async:简洁优雅的异步之道
  • 原文地址:https://www.cnblogs.com/FallDream/p/usaco2017Feb.html
Copyright © 2020-2023  润新知