zoukankan      html  css  js  c++  java
  • NOIP2011提高组

    D1T1.铺地毯

    for循环

    #include<iostream>  
    #include<cstdio> 
    #include<algorithm>  
    using namespace std;  
    struct hp{ 
        int a,b,g,k; 
    }map[10001]; 
    int main()  
    {  
        int n,i,x,y; 
        cin>>n; 
        for(i=1;i<=n;i++) 
        cin>>map[i].a>>map[i].b>>map[i].g>>map[i].k; 
        cin>>x>>y; 
        for(int i=n;i>=1;i--) 
        { 
            if(map[i].a<=x&&map[i].a+map[i].g>=x&&map[i].b<=y&&map[i].b+map[i].k>=y) 
            {cout<<i<<endl;return 0;} 
        } 
        cout<<"-1"<<endl; 
        return 0;  
    }  
    View Code

    D1T2.选择客栈

    这道题O(kn)算法很简单啊,我来讲讲O(n)的算法吧

    a[c]表示记录到第i个客栈为止色调为c的客栈的总数

    b[c]表示记录到离当前客栈i最近的消费水平不高于p的客栈为止色调为c的客栈的数量

    s[c]记录到当前客栈i为止,最后一个色调为c的客栈的编号

    f记录距离客栈i最近的消费水平不超过p的客栈的编号

    每读入一个客栈的色调c和最低消费v,我们首先来判断v是否超过了p,如果v没有超过p的话,我们让f=i,即先更新f。

     每读入一组数据c和v,我们就应该更新a[c]和s[c],但是在这一步之前,我们要做如下操作:

    不管当前客栈i的消费水平如何,我们来比较f和最后一个色调为c的客栈的编号s[c]的大小关系,

    由于我们还没有更新s[c],所以这次比较不包含当前客栈i;

    对于当前客栈i的色调c来说,如果该色调是在编号为f的客栈之后第一次出现,则必有f>=s[c],那么a[c]里面记录的必然是在f客栈之前(包括f)色调为c的客栈的数量,这时我们让b[c]=a[c],

    如果色调c在客栈f之后出现的次数多于1次,那么我们必然已经更新过s[c],那么必然有s[c]>f,这时我们不做任何操作,则b[c]内保存的依然是在客栈f之前(包括f)色调为c的客栈的数量。

    在这里,f发生变化与否,对结果是没有影响的,因为即便在这一步之前f发生了变化,如果某个色调c一直没有出现的话,那对结果没有任何影响,

    而一旦某个色调在f变化之后第一次出现,必然有f>=s[c],这时必然要更新b[c],那么b[c]必然在这里就会更新成为我们后面计算需要的正确的值,而且在f再次变化之前,b[c]将保持不变。

    #include<cstdio>
    int a[51],b[51],s[51],f=0,n,k,p,c,v,ans=0;
    int main()
    {
        scanf("%d%d%d",&n,&k,&p);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&c,&v);
            if(v<=p)f=i;
            if(f>=s[c])b[c]=a[c];
            ans+=b[c];a[c]++;s[c]=i;
        }
        printf("%d",ans);
        return 0;
     }
    View Code

    D1T3 Mayan游戏

    搜索+剪枝

    1.因为1优先于-1,所以如果一个方块左边也有方块,那么不用搜索这个状态

    2.直接从地图的左下角按从下到上,从左到右的顺序搜索

    #include<iostream>  
    #include<cstdio> 
    #include<cstring> 
    #include<cstdlib> 
    #include<algorithm> 
    using namespace std; 
    bool ret=0; 
    int mp[9][7],n,ansx[6],ansy[6],ansg[6]; 
    void diao() 
    { 
        int w[6];memset(w,0,sizeof(w)); 
        for(int j=1;j<=5;j++) 
        for(int i=7;i>=1;i--) 
        { 
            if(!mp[i][j]){w[j]=i;break;} 
        } 
        for(int i=7;i>=1;i--) 
        for(int j=1;j<=5;j++) 
        { 
            if(mp[i][j]) 
            { 
                if(i>w[j])continue; 
                mp[w[j]][j]=mp[i][j];mp[i][j]=0;w[j]--; 
            } 
        } 
    } 
    bool xiao() 
    { 
        int _mp[8][6];bool ok=0; 
        for(int i=1;i<=7;i++)for(int j=1;j<=5;j++)_mp[i][j]=mp[i][j]; 
        for(int i=1;i<=7;i++) 
        { 
            int j=1; 
            while(j<=5) 
            { 
                if(_mp[i][j]==0){j++;continue;}int stop; 
                for(stop=j+1;stop<=5;stop++)if(_mp[i][stop]!=_mp[i][stop-1])break; 
                if(stop-j>=3){for(;j<stop;j++)mp[i][j]=0;ok=1;} 
                else j=stop; 
            } 
        } 
        for(int j=1;j<=5;j++) 
        { 
            int i=1; 
            while(i<=7) 
            { 
                if(_mp[i][j]==0){i++;continue;}int stop; 
                for(stop=i+1;stop<=7;stop++)if(_mp[stop][j]!=_mp[stop-1][j])break; 
                if(stop-i>=3){for(;i<stop;i++)mp[i][j]=0;ok=1;} 
                else i=stop; 
            } 
        } 
        return ok; 
    } 
    void dfs(int t) 
    { 
        if(ret)return; 
        int _mp[8][6]; 
        if(t>n) 
        { 
            bool ok=0; 
            for(int i=1;i<=7;i++) 
            for(int j=1;j<=5;j++)if(mp[i][j])ok=1; 
            if(!ok) 
            { 
                for(int i=1;i<=n;i++)printf("%d %d %d
    ",ansx[i],ansy[i],ansg[i]); 
                ret=1; 
                return; 
            } 
            return; 
        } 
        int color[11];memset(color,0,sizeof(color)); 
        bool ok=0; 
        for(int i=1;i<=7;i++)for(int j=1;j<=5;j++) 
        { 
            _mp[i][j]=mp[i][j];color[mp[i][j]]++;if(mp[i][j])ok=1; 
        } 
        if(!ok)return; 
        for(int i=1;i<=10;i++)if(color[i]>0&&color[i]<3)return; 
        for(int j=1;j<=5;j++) 
        for(int i=7;i>=1;i--) 
        { 
            if(mp[i][j]==0)continue; 
            if(j!=5) 
            { 
                swap(mp[i][j],mp[i][j+1]); 
                do{ 
                    diao(); 
                }while(xiao()); 
                ansx[t]=j-1;ansy[t]=7-i;ansg[t]=1;dfs(t+1); 
                for(int i=1;i<=7;i++)for(int j=1;j<=5;j++)mp[i][j]=_mp[i][j]; 
            } 
            if(j!=1) 
            { 
                if(mp[i][j-1]!=0)continue; 
                swap(mp[i][j],mp[i][j-1]); 
                do{ 
                    diao(); 
                }while(xiao()); 
                ansx[t]=j-1;ansy[t]=7-i;ansg[t]=-1;dfs(t+1); 
                for(int i=1;i<=7;i++)for(int j=1;j<=5;j++)mp[i][j]=_mp[i][j]; 
            } 
        } 
    } 
    int main() 
    { 
        scanf("%d",&n); 
        for(int i=1;i<=5;i++) 
        for(int j=1;j<=8;j++) 
        { 
            scanf("%d",&mp[8-j][i]);if(!mp[8-j][i])break; 
        } 
        dfs(1); 
        if(!ret)printf("-1"); 
        return 0; 
     }  
    View Code

    D2T1 计算系数

    杨辉三角

    #include<iostream>  
    using namespace std;  
    int dp[1002][1002];const int mod=10007;  
    int main()  
    {  
        int a,b,k,n,m;scanf("%d%d%d%d%d",&a,&b,&k,&n,&m);  
        for(int i=1;i<=k+1;i++)dp[i][i]=1,dp[i][1]=1;  
        for(int i=3;i<=k+1;i++)  
        for(int j=2;j<i;j++)dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;  
        long long ans=dp[k+1][m+1];  
        for(int i=1;i<=n;i++)ans=(ans*a)%mod;  
        for(int i=1;i<=m;i++)ans=(ans*b)%mod;  
        cout<<ans;  
        return 0;  
    }  
    View Code

    D2T2 聪明的质检员

    首先分析公式计算,容易发现sigma ci会随着 m 的递增单调递减。
    因此答案满足了单调性,我们考虑二分答案 m,然后对于每次二分出来的答案check 的话,时间复杂度太高。

    我们可以发现,可以使用前缀和来 O(1)回答区间查询,对于每个二分出来的 m,先花 O(n)的时间按题意做一下前缀和,然后再 O(q)计算一下 sigma,

    这样的话就可以把每次二分完的 O(nq)优化到 O(n+q),总时间复杂度为O((n+q)log2S)

    #include<cstring> 
    #include<cstdio> 
    #include<algorithm> 
    using namespace std; 
    int w[200001],v[200001],l[200001],r[200001],sw[200001],b[200001],c[200001]; 
    int main() 
    { 
        int n,m;long long s;scanf("%d%d%lld",&n,&m,&s); 
        for(int i=1;i<=n;i++){scanf("%d%d",&w[i],&v[i]);sw[i]=w[i];} 
        for(int i=1;i<=m;i++)scanf("%d%d",&l[i],&r[i]); 
        sort(sw+1,sw+n+1); 
        long long ans=999999999999LL;int _l=1,_r=n+1; 
        while(_l<_r) 
        { 
            int mid1=(_l+_r)/2; 
            int mid=sw[mid1]; 
            b[0]=0;c[0]=0; 
            for(int i=1;i<=n;i++) 
            { 
                int g=v[i];c[i]=c[i-1]; 
                if(w[i]<mid)g=0; 
                else c[i]++; 
                b[i]=b[i-1]+g; 
            } 
            long long x=0; 
            for(int i=1;i<=m;i++)x+=(b[r[i]]-b[l[i]-1])*(c[r[i]]-c[l[i]-1]); 
            if(x<s)_r=mid1; 
            else _l=mid1+1; 
            ans=min(ans,abs(x-s)); 
        } 
        printf("%lld",ans); 
        return 0; 
    } 
    View Code

    D2T3 观光公交

        sum[i]:在前i站下车的人的总数;las[i]:最晚的一个人的到达i站的时间;get[i]最早的到达i站时间。

        那么,题目所求的问题就是∑(get[b[i]]-t[i])。

        可以转化为:∑(get[b[i]])-∑(t[i])。而∑(t[i])是定值,于是就是要使∑(get[b[i]])最小。

        至于get[i],它取决于上一站的到站时间和最晚的一个人,get[i]=max(las[i-1],get[i-1])+d[i-1]。

        容易想到,如果一个d[i]减小了,那么它肯定会影响到后面的一段连续的get[i]。

        具体地来说,如果get[i]>las[i],也就是车的最早到达时间要晚于最慢的人的到达时间,那么前面如果用了加速器,那么就能使get[i]减小,否则就不能造成影响。

        我们开一个数组g[i]表示如果d[i]减小,那么最多影响到后面的哪个站。很明显,随着d[i]的减小,g[i]是要变的。

        g[i]=g[i+1](get[i+1]>las[i+1],后一个站的出发时间由到达时间决定)   或   i+1(get[i+1]<=las[i+1],后一个站的出发时间由最晚到达的人决定)。

        要使加速器的效果最大,那么就要使这个加速器的作用影响到最多的人,于是每次找sum[g[i]]-sum[i]最大的一个d[i]加速(d[i]>0)。重复k次即可。

        每一个加速器互不影响,所以不存在后效性,局部最优即是全局最优。

    #include<iostream> 
    #include<cstdio> 
    using namespace std; 
    int n,m,k,sum[1001],las[1001],get[1001],g[1001],ans=0; 
    int d[1001],a[10001],b[10001],t[10001]; 
    int main() 
    { 
        scanf("%d%d%d",&n,&m,&k); 
        for(int i=1;i<n;i++)scanf("%d",&d[i]); 
        for(int i=1;i<=m;i++) 
        { 
            scanf("%d%d%d",&t[i],&a[i],&b[i]); 
            las[a[i]]=max(las[a[i]],t[i]);sum[b[i]]++; 
        } 
        for(int i=1;i<=n;i++)sum[i]+=sum[i-1]; 
        for(int i=1;i<=n;i++) 
        { 
            get[i]=max(get[i-1],las[i-1])+d[i-1]; 
        } 
        g[n]=n; 
        for(int i=n-1;i>=1;i--) 
        { 
            if(get[i+1]>las[i+1])g[i]=g[i+1]; 
            else g[i]=i+1; 
        } 
        for(int i=1;i<=m;i++)ans+=get[b[i]]-t[i]; 
        while(k) 
        { 
            int rs=0,l,r; 
            for(int i=1;i<n;i++) 
            { 
                if(sum[g[i]]-sum[i]>rs&&d[i]) 
                { 
                    rs=sum[g[i]]-sum[i];l=i;r=g[i]; 
                } 
            } 
            d[l]--;ans-=rs; 
            for(int i=l;i<=r;i++) 
            { 
                get[i]=max(get[i-1],las[i-1])+d[i-1]; 
            } 
            if(r==n)r--;g[n]=n; 
            for(int i=r;i>=l;i--) 
            { 
                if(get[i+1]>las[i+1])g[i]=g[i+1]; 
                else g[i]=i+1; 
            } 
            k--; 
        } 
        printf("%d",ans); 
        return 0; 
    } 
    View Code
  • 相关阅读:
    http://www.bugku.com:Bugku——SQL注入1(http://103.238.227.13:10087/)
    [笔记]一道C语言面试题:大整数乘法
    [笔记] Access Control Lists (ACL) 学习笔记汇总
    [笔记]如何将传统的回调函数转换为C#5.0支持的await格式
    6.链接与导航
    9章 下拉菜单
    11章圆角框 本章很重要 经常用到
    原来链接与导航
    7竖直排列的导航菜单
    8.水平导航菜单
  • 原文地址:https://www.cnblogs.com/lher/p/6789090.html
Copyright © 2011-2022 走看看