zoukankan      html  css  js  c++  java
  • 套题 bestcoder 84

    A题:Aaronson

    静下心来观察就会发现
    1.如果m大于等于n的位数,那么n直接写成二进制形式就是最优解形式
    2.如果m小于n的位数,那么贪心地使得高位尽可能地多消掉n的值,因为高位少写一个数
    就意味着低位要写更多位来弥补抵消
    3.在第二种情况下,枚举2^m也不会超int,因为(n<le9)最多有30位,且m小于n的位数
    ,m就不会很大

    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e5+10;
    inline int cacu(int x)
    {
        int ans=0;
        while(x)
        {
            ans++;
            x/=2;
        }
        return ans;
    }
    int main()
    {
        int T;
        for(scanf("%d",&T);T;T--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            m+=1;
            int c=cacu(n);
            int sum;
            if(m>=c)
            {
              sum=0;
              while(n)
              {
                  if(n&1) sum+=1;
                  n>>=1;
              }
            }
            else
            {
                sum=0;
                int re;
                while(n)
                {
                   re=n/(1<<(m-1));
                   sum+=re;
                   n=n-re*(1<<(m-1));
                   m--;
                }
            }
            cout<<sum<<endl;
        }
        return 0;
    }
    View Code

    B题:Bellovin
    给出一个序列,求与这个序列LIS相同的最小字母序序列

    观察可知,答案即为求每位LIS
    以dp[x]代表长度为x的LIS,且dp[x]==LIS长度为x的末尾值
    每次都往前取dp[x]中最小的一个,当然在保证x尽可能地大的情况下
    因为dp[x]是递增的,所以可以二分,l=1,r=当前最长的LIS
    求得当前以小于当前a[i]的最长LIS

    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e5+10;
    int A[Max];
    int dp[Max];
    int LIS[Max];
    void Get_lis(int n)
    {
        int i,j,l,r,mid,ans;
        dp[1]=A[1];
        int len=1;
        for(i=2;i<=n;i++)
        {
            if(dp[len]<A[i]) j=++len;
            else
            {
                l=1;r=len;
                ans=0;
                while(l<=r)
                {
                    mid=(l+r)>>1;
                    if(A[i]>dp[mid]&&A[i]<=dp[mid+1])
                    {
                        ans=mid;break;
                    }
                    else if(A[i]>dp[mid]) l=mid+1;
                    else r=mid-1;
                }
                j=ans+1;
            }
            dp[j]=A[i];
            LIS[i]=j;
        }
    }
    int main()
    {
        int T;
        for(scanf("%d",&T);T;T--)
        {
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&A[i]);
                dp[i]=0;
            }
            LIS[1]=1;
            Get_lis(n);
            for(int i=1;i<=n;i++)
            {
                if(i!=1) printf(" ");
                printf("%d",LIS[i]);
            }
            puts("");
        }
        return 0;
    }
    View Code

    C题:Colmerauer
    已知一个鞍点可覆盖范围是一个矩形,以这个鞍点作为原点
    可以利用单调栈求出它的(u,l,d,r)
    在枚举子矩阵的时候,会有多少次覆盖到这个鞍点的区域?
    不如思考一下这个鞍点的区域可以分成多少个子矩阵
    分类:
    将鞍点看做原点0,那么原本的左右区间可以写成(-l,r);
    鞍点在x轴上可以分为三部分:(-l,0,r)
    那么左边的长度有l种,右边也有r种
    分类法加分步法分析:
    第一种:先选左边:那么左边l种区间的长度和为(l)(l+1)/2,因为此时右边可以任选,
    ,有r+1(包括原点)种方式,再乘以r+1
    第二种:先选右边: 那么右边(r+1)(包括鞍点自身)种区间的长度和为(r+1)(r+2)/2,因为
    此时左边可以任选,有l+1种方式,再乘以l+1
    鞍点在y轴上的区分求法同上
    注意此题求出的l,r,u,d比实际值高了一位

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MOD=(LL)(1<<20)*(LL)(1<<12);
    const int Max=1e3+10;
    const int inf=0x3f3f3f3f;
    int matrix[Max][Max],l[Max][Max],r[Max][Max],
    u[Max][Max],d[Max][Max];
    stack<int>st;
    LL Cacu(int x,int y)
    {
       LL ans=(x*(x+1)/2*(y+1)%MOD+(y+1)*(y+2)/2*(x+1)%MOD)%MOD;
       return ans;
    }
    int main()
    {
        int T;
        for(scanf("%d",&T); T; T--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
                    scanf("%d",&matrix[i][j]);
    
            //行中最小
            for(int i=1; i<=n; i++)
            {
                matrix[i][m+1]=matrix[i][0]=-inf;
                while(!st.empty()) st.pop();
                st.push(0);
                for(int j=1; j<=m; j++)
                {
                    while(!st.empty()&&matrix[i][st.top()]>matrix[i][j]) st.pop();
                    l[i][j]=st.top();
                    st.push(j);
                }
                while(!st.empty()) st.pop();
                st.push(m+1);
    
                for(int j=m; j>=1; j--)
                {
                    while(!st.empty()&&matrix[i][st.top()]>matrix[i][j]) st.pop();
                    r[i][j]=st.top();
                    st.push(j);
                }
            }
    
            //列中最大
            for(int j=1; j<=m; j++)
            {
                matrix[0][j]=matrix[n+1][j]=inf;
                //这里是为了保证u[1]=0和d[n]=n+1,因此要设到最大
                while(!st.empty()) st.pop();
                st.push(0);
                for(int i=1; i<=n; i++)
                {
                    while(!st.empty()&&matrix[st.top()][j]<matrix[i][j]) st.pop();
                    u[i][j]=st.top();
                    st.push(i);
                }
                while(!st.empty()) st.pop();
                st.push(n+1);
                for(int i=n; i>=1; i--)
                {
                    while(!st.empty()&&matrix[st.top()][j]<matrix[i][j]) st.pop();
                    d[i][j]=st.top();
                    st.push(i);
                }
            }
          LL ans=0;
          int uy,dy,lx,rx;
          for(int i=1;i<=n;i++)
          {
              for(int j=1;j<=m;j++)
              {
                  uy=i-u[i][j]-1;lx=j-l[i][j]-1;
                  dy=d[i][j]-i-1;rx=r[i][j]-j-1;
                  ans=(ans+(Cacu(uy,dy)*Cacu(lx,rx)%MOD*matrix[i][j]))%MOD;
              }
          }
          printf("%I64d
    ",ans);
        }
        return 0;
    }
    View Code

    D题:Dertouzos
    求1到n-1中最大因数是d的数的个数
    设m是1到n-1的任意一个数
    设m=d*r,若d是m的最大因数,r必须满足:
    1.r必然是m的最小因数,
    2.r必然是素数,不然总可以拆成另外的几个数,导致存在比d大的因数
    3.r必然小于等于d
    可以看到,m最大是n-1,r最大是n-1/d
    那么可以从最小素数2开始进行检查,看其是否能成为r
    1到1e9的素数筛出来,过于艰难
    通过观察可以发现:
    当d很小时,由于r小于等于d,循环d次即可
    当d很大时,由于r小于等于n-1/d,循环次数也不会很多
    可以将d<=1e4时当作很小进行分析:
    d<=1e4,r不会超过1e4
    d>1e4,n最高等于1e9,n-1/d<=1e5,r不会超过1e5
    因此我们只要筛出1到1e5的素数就好了

    #include <bits/stdc++.h>
    using namespace std;
    const int Max=1e7+10;
    int prime[Max],is_prime[Max],top;
    void Erato()
    {
        int m,n;
        n=1e5+5;
        for(int i=2; i<=n; i++) if(!is_prime[i])
            {
                prime[top++]=i;
                for(int j=i*2; j<=n; j+=i) is_prime[j]=1;
            }
    }
    int check(int n,int d)
    {
        int ans=0;
        for(int i=0; i<top; i++)
        {
            if(d*prime[i]>=n) return ans;
            if(d%prime[i]==0) return ans+1; //包括自身
            ans++;
        }
        return ans;
    }
    int main()
    {
        Erato();
        int T;
        for(scanf("%d",&T); T; T--)
        {
            int n,d;
            scanf("%d%d",&n,&d);
            int ans=check(n,d);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    E题:Eades
    待续。。。。。。

  • 相关阅读:
    Vue项目入门实例
    批量生成删除表数据的SQL语句
    收集的一个可多选日期的日期插件,带日历、农历
    .net core EF,多个dbcontext时,迁移数据方法
    【NET】雪花算法
    URL地址中使用中文作为的参数【转】
    C# 继承 base
    SQL Like
    SecureCRT 8.5 配置自动记录日志
    CentOS 7下Samba服务器的安装与配置
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/5708705.html
Copyright © 2011-2022 走看看