zoukankan      html  css  js  c++  java
  • [APIO2015]题解

    说实话今年的APIO不是太难

    但仍然阻止不了我酱油

    26分TAT

    巴厘岛的雕塑、巴邻旁之桥暴力

    摩天楼那题SPFA莫名写跪了

    第一题知道是动规不会写方程TAT

    膜拜cstdio的位运算

    第一题 巴厘岛的雕塑

    题目大意是N个数,分为[A,B]个组

    使得每组求和后异或和最小

    话说为什么是最小TAT,强行黑一波印尼政府

    9分算法

    每两个之间判断放不放隔板,时间复杂度O(2^n)

    71分算法

    考虑贪心

    从答案(二进制)的最高位到最低位,逐位判断是否能为0

    定义状态f[i][j]

    表示前i个数分成j位满足前答案前k-1位的是否可行,且k=1

    然后枚举区间[A,B],判断是否对于A<=i<=B,存在f[n][i]=true,如果存在,则该位可以为0

    时间复杂度O(log2M*N^3)

    M为答案十进制长度

    100分算法

    我们注意到最后一组数据A=1,也就是没有下限,于是我们用一维数组F[i]

    代替f[i][j],

    F[i]表示前i个数最少要分为几组,最后判断是否F[n]<=B即可

        #include <fstream>
        //#include <iostream>
        #include <cstring>
        #define LL long long
        using namespace std;
        ifstream cin("sculpture.in");
        ofstream cout("sculpture.out");
        int n,a,b;
        int A[2001]={0};
        bool f[2001][2001]={0};
        long long S[2001]={0};
        long long limit;
        int F[2001]={0};
        long long bark(int x)
        {
            long long ans=1;
            ans=ans<<x;
            //cout<<ans<<endl;
            return ans;
        }
        bool mark()
        {
            int i,j,k;
            memset(f,0,sizeof(f));
            f[0][0]=1;
            for(i=0;i<n;i++)
            {
                for(j=0;j<b;j++)
                {
                    if(f[i][j])
                    {
                        for(k=i+1;k<=n;k++)
                        {
                            if(((S[k]-S[i])|limit)==limit)
                            {
                                f[k][j+1]=1;
                            }
                        }
                    }
                }
            }
            //cout<<a<<' '<<b<<endl;
            for(k=a;k<=b;k++)if(f[n][k])return 1;
            return 0;
        }
        bool dark()
        {
            int i,j,k;
            memset(F,63,sizeof(F));
            F[0]=0;
            for(i=0;i<n;i++)
            {
                for(k=i+1;k<=n;k++)
                {
                    if(((S[k]-S[i])|limit)==limit)
                    {
                        F[k]=min(F[k],F[i]+1);
                    }
                }
            }
            return F[n]<=b;
        }
        void judge(int x)
        {
            bool OK=0;
            limit-=bark(x);
            if(a!=1)OK=mark();
            if(a==1)OK=dark();
            //cout<<OK<<endl;
            if(!OK)limit+=bark(x);
        }
        int main()
        {
            int i,j,k;
            cin>>n>>a>>b;
            for(i=1;i<=n;i++)cin>>A[i];
            for(i=1;i<=n;i++)S[i]=S[i-1]+A[i];
            //for(i=1;i<=n;i++)cout<<S[i]<<' ';
            limit=bark(46)-1;
            //cout<<limit<<endl;
            for(i=45;i>=0;i--)judge(i);
            cout<<limit<<endl;
            return 0;
        }

    第二题 雅加达的摩天楼

    题目大意:

    有N个建筑物,M只狗

    告诉每只狗的初始建筑物位置b

    和跳跃能力p

    每只狗一步可以调到b+p或b-p的建筑物上

    求0号狗到1号狗最少需要的跳跃步数

    很容易看出这题是一个最短路径问题

    关键在建边

    10分算法

    强行一波DFS(尼玛比正解还难打估计没人打)

    22分算法

    把每只狗能到达的所有位置建边,边的数量会爆

    57分算法

    稍微加一个优化即可,只与有狗的建筑物建边

    100分算法(伪)

    由于题目数据略水,不需要加什么特别强的优化

    去掉同一个建筑物上跳跃能力相同的狗,对某些数据可以大大加快速度

    97分算法(UOJ)

    /*以下内容本人并不会,摘自http://blog.csdn.net/regina8023/article/details/45766241,感谢作者

    考虑分块

    对于跳跃能力大于sqrt(n)的狗,我们直接建边

    对于跳跃能力小于sqrt(n)的狗,

    我们可以在后面添加一些辅助点来实现预处理:
    枚举这sqrt(n)个长度,在后面分别建n个辅助点,连向前面对应的位置,同时连向可以来自和到达的辅助点。

    对于读入直接连向他对应的辅助点即可。*/

    对于最短路径的求法,我推荐Dij,因为本题十分特殊,边的数量远远大于点的数量,用SPFA较快

    可是我不知道为什么我的加优先队列的DIJ会挂一组

    最后还是用了SPFA,注:我下面的程序没有分块

    #include <fstream>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <string.h>
    #include <map>
    using namespace std;
    ifstream cin("skyscraper.in");
    ofstream cout("skyscraper.out");
    int n,m;
    bool l[30001]={0};
    vector<int> D[30001],G[30001],C[30001],A,Q,E[30001];
    int len[30001]={0};
    int f[30001]={0};
    bool visit[30001]={0};
    int INF=9999999;
    class node
    {
    public:
        int x;
        int y;
    }ab[30001];
    map<node,bool>F;
    void SPFA(int s) { // SPFA
        queue<int> q;
        l[s] = 1;
        fill_n(f, n, INF); f[s] = 0;
        q.push(s);
        while(!q.empty()) {
            int u = q.front(); q.pop();
            l[u] = 0;
            for(int i=0; i<G[u].size(); i++) {
                int v = G[u][i];
                if(f[v] > f[u] + C[u][i]) {
                    f[v] = f[u] + C[u][i];
                    if(!l[v]) {
                        l[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    int main()
    {
        int i,j,k,a,b,start,end;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            cin>>ab[i].x>>ab[i].y;
            visit[ab[i].x]=1;
        }
        for(i=1;i<=m;i++)
        {
            a=ab[i].x;
            b=ab[i].y;
            int c=ab[i-1].x;
            int d=ab[i-1].y;
            if(a==c&&b==d&&i>=10)continue;
            for(j=a+b;j<=n;j+=b)
            {
                //cout<<j<<' '<<endl;
                if(!visit[j])continue;
                G[a].push_back(j);
                C[a].push_back((j-a)/b);
            }
            for(j=a-b;j>=0;j-=b)
            {
                if(!visit[j])continue;
                G[a].push_back(j);
                C[a].push_back((a-j)/b);
            }
            if(i==1)start=a;
            if(i==2)end=a;
        }
        //memset(l,sizeof(l),0);
        SPFA(start);
        if(start==end)cout<<0<<endl;
        else if(f[end]!=INF)cout<<f[end]<<endl;
        else cout<<-1<<endl;
        return 0;
    }

    第三题:巴邻旁之桥

    题目大意比较麻烦,这里就不说了

    家和办公室的同一侧的,预处理提前算好

    我们可以通过暴力程序和或手算发现,

    当k=1时,我们目标是最小化|a-x|+|b-x|

    不难发现答案是所有家和办公室的中位数(考场上只顾着打暴力啦)

    /*以下内容本人还没有掌握,摘自http://www.bubuko.com/infodetail-809274.html

    对于k=2时

    按照每个人的家和办公室的中点排序后,一定存在一个分割点使得前缀都走左边的桥,后缀都走右边的桥(因为走靠近中点的桥不会更差)。

    于是我们枚举分割点,离散化后用权值线段树动态维护两个区间的中位数求解即可。*/然而我并不会写线段树

    目前我只拿到了31分

    31分算法

    //May 20 2015
    //By Satoshi
    //#include <iostream>
    #include <fstream>
    #include <vector>
    #include <algorithm>
    #include <map>
    #define LL long long
    using namespace std;
    ifstream cin("cstdiorank1AK.in");
    ofstream cout("cstdiorank1AK.out");
    int aa[100001]={0},bb[100001]={0};
    int cc[200001]={0};
    LL ans=0;
    int n,K;
    map<int,bool>F;
    vector<int> q;
    void work1()
    {
        int pos,i;
        pos=cc[n];
        //out<<pos<<endl;
        for(i=1;i<=n;i++)
        {
            //out<<ans<<endl;
            ans+=abs(pos-bb[i])+abs(pos-aa[i])+1;
        }
    }
    void work2()
    {
        int i,j,k;
        LL best=1LL<<51;
        LL sum=0;
        LL u,v,w;
        for(i=0;i<q.size()-1;i++)
        {
            for(j=i+1;j<q.size();j++)
            {
                sum=0;
                for(k=1;k<=n;k++)
                {
                    u=abs(aa[k]-q[i])+abs(bb[k]-q[i]);
                    v=abs(aa[k]-q[j])+abs(bb[k]-q[j]);
                    w=min(u,v)+1;
                    sum+=w;
                }
                if(sum<best)best=sum;
            }
        }
        ans+=best;
    }
    int main()
    {
        char a,c;
        int i,j;
        int b,d;
        int size=0;
        cin>>K>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a>>b>>c>>d;
            if(a==c)ans+=abs(b-d);
            else
            {
                size++;
                aa[size]=b;
                bb[size]=d;
            }
            if(F[b]==0)
            {
                q.push_back(b);
                F[b]=1;
            }
            if(F[d]==0)
            {
                q.push_back(d);
                F[d]=1;
            }
        }
        n=size;
        //out<<ans<<endl;
        for(i=1;i<=n;i++)
        {
            cc[i]=aa[i];
            cc[n+i]=bb[i];
        }
        sort(cc+1,cc+2*n+1);
        //for(i=1;i<=n*2;i++)out<<cc[i]<<' ';
        if(K==1)work1();
        if(K==2)work2();
        //for(i=0;i<q.size();i++)out<<q[i]<<' ';
        
        cout<<ans<<endl;
        return 0;
    }

    如有错误请指出,谢谢(^_^)

  • 相关阅读:
    Codeforces Round #336 B
    Codeforces Round #336 A
    hiho一下157
    Codeforces Round #420 E
    Codeforces Round #420 C
    Codeforces Round #420 B
    Codeforces Round #420 A
    Codeforces Round #418 C
    Codeforces Round #418 B
    CodeForces 811D Vladik and Favorite Game bfs,模拟
  • 原文地址:https://www.cnblogs.com/Satoshi/p/4524805.html
Copyright © 2011-2022 走看看