zoukankan      html  css  js  c++  java
  • SRM 548 DIV2

    250pt

    数学模型:

      给定一个数组,求不同整数的种数*出现次数最多的数的次数。

    分析:

      因为数字范围有限,暴力模拟即可

    View Code
    class KingdomAndDucks 
    { 
            public: 
            int minDucks(vector <int> d) 
            { 
                int i,j,k,n=d.size(),a[55]={0};
                for(i=0;i<n;i++)
                    a[d[i]]++;
                for(i=k=j=0;i<55;i++)
                    if(a[i])
                        j++,k=max(a[i],k);
                return j*k;
            } 
            
     
    }; 


    500pt:

    数学模型:

      给定一个数字序列,定义一个数字n,使序列中的每个数可以最多增加或减少n。求n的最小值,使该序列单调递增。

    分析:

      因为数字范围是10^9,动态规划不现实,考虑贪心;

      如果n已求出,n-1肯定不符合条件,n+1肯定符合条件,答案n具有单调性,可以二分枚举答案用贪心构造

      效率是O(nlog(m))

    O(nlog(m))
    class KingdomAndTrees 
    { 
            public: 
            int minLevel(vector <int> a) 
            { 
                    int low,high,mid,i,k,pre;
                    int n=a.size();
                    for(low=0,high=1000000000;low<=high;)
                    {
                        mid=(low+high)>>1;
                        pre=0;
                        for(i=0;i<n;i++)
                        {
                            if(a[i]<=pre)
                            {
                                if(a[i]+mid>=pre+1)
                                    pre++;
                                else
                                    break;
                            }
                            else
                            {
                                if(a[i]-mid<=pre+1)
                                    pre++;
                                else
                                    pre=a[i]-mid;
                            };
                        }
                        if(i<n)
                            low=mid+1;
                        else
                            k=mid,high=mid-1;
                    }
                    return k;
            } 
            
    }; 


    1000pt

    数学模型:

      给定两个位数相同的整数m和n,用m的各位数字构造一个新的数,使各位数字都不同于n且与m的差距最小。

    分析:也是在一定条件下求最小,尝试使用贪心加枚举,没解决,只能深度搜索,但不知怎么写。看了官方的解题报告,果然。

      剪枝,搜下界时从大数开始枚举位,搜上界时从小数开始枚举位,再纪录已经搜索好的结果,f[s][i][ok]很神奇

      求下界时,f[s][i][ok]表示用状态为s(s的每个二进制位表示一个状态,表示该数字是否已被使用)的i位数

        ok=1时,f[s][i][ok]的表示能否构成小于oldPassword前i位对应的整数值

        ok=0时,f[s][i][ok]的表示能否构成等于oldPassword前i位对应的整数值

      上届亦然。

    结:剽窃的思想解题报告都难写。

      一碰到复杂度不可估计的深搜就不敢写,没有信心,总是改不了这个毛病。

      只有通过多做深搜题目来克服。。。

      解决满足一定条件下和给定数差距最小的值,除了贪心+枚举外,还可用此方法,DFS+f[][][]

    DFS
    int f[1<<17][17][2];
    class KingdomAndPassword 
    { 
            public:
    
            int res[16],cs[16],old[16],n;
            vector<int> rt;
    
            int lower(int s,int i, int ok)
            {
                if(f[s][i][ok]!=-1)
                    return f[s][i][ok];
                if(i==n)
                {
                    f[s][i][ok]=ok;
                    return ok;
                }
                f[s][i][ok]=0;
                for(int j=n-1;j>=0;j--)
                    if((s&(1<<j))==0 && rt[i]!=cs[j] && (ok||cs[j]<=old[i]) )
                        if(lower(s|(1<<j) , i+1 , ok|(cs[j]<old[i])))
                        {
                            f[s][i][ok]=1;
                            return 1;
                        }
                
                return 0;
            }
    
            void find_lower(int s,int i, int ok)
            {
                if(i==n)
                    return ;
                for(int j=n-1;j>=0;j--)
                    if((s&(1<<j))==0&&rt[i]!=cs[j]&&(ok||cs[j]<=old[i]))
                        if(lower(s|(1<<j),i+1,ok|(cs[j]<old[i])))
                        {
                            res[i]=cs[j];
                            find_lower(s|(1<<j),i+1,ok|(cs[j]<old[i]));
                            return ;
                        }
            }
    
            int upper(int s,int i, int ok)
            {
                if(f[s][i][ok]!=-1)
                    return f[s][i][ok];
                if(i==n)
                {
                    f[s][i][ok]=ok;
                    return ok;
                }
                f[s][i][ok]=0;
                for(int j=0;j<n;j++)
                    if((s&(1<<j))==0&&rt[i]!=cs[j]&&(ok||cs[j]>=old[i]))
                        if(upper(s|(1<<j),i+1,ok|(cs[j]>old[i])))
                        {
                            f[s][i][ok]=1;
                            return 1;
                        }
                return 0;
            }
    
            void find_upper(int s,int i, int ok)
            {
                if(i==n)
                    return ;
                for(int j=0;j<n;j++)
                    if((s&(1<<j))==0&&rt[i]!=cs[j]&&(ok||cs[j]>=old[i]))
                        if(upper(s|(1<<j),i+1,ok|(cs[j]>old[i])))
                        {
                            res[i]=cs[j];
                            find_upper(s|(1<<j),i+1,ok|(cs[j]>old[i]));
                            return ;
                        }
            }
    
            long long newPassword(long long oldPassword, vector <int> restrictedDigits) 
            { 
                    int i;
                    LL a=-1,b=-1;
                    LL m=oldPassword;
                    for(n=0;m;m/=10)
                        cs[n++]=m%10;
                    for(i=0;i<n;i++)
                        old[i]=cs[n-i-1];
                    rt=restrictedDigits;
                    for(i=0;i<n;i++)
                        if(rt[i]==old[i])
                            break;
                    if(i==n)
                        return oldPassword;
                    sort(cs,cs+n);
                    memset(f,-1,sizeof(f));
                    if(lower(0,0,0))
                    {
                        find_lower(0,0,0);
                        for(a=0,i=0;i<n;i++)
                            a=a*10+res[i];
                    }
                    memset(f,-1,sizeof(f));
                    if(upper(0,0,0))
                    {
                        find_upper(0,0,0);
                        for(b=0,i=0;i<n;i++)
                            b=b*10+res[i];
                    }
                    if(a==-1)return b;
                    if(b==-1)return a;
                    return abs(oldPassword-a)<=abs(oldPassword-b)?a:b;
            } 
            
     
    }; 
  • 相关阅读:
    树链剖分(转载)
    随机数生成器
    错排公式的理解与推导(转载)
    容斥原理(转载)
    Luogu 3758 [TJOI2017]可乐(有向图邻接矩阵幂的意义 矩阵快速幂)
    vue input复选框checkbox默认样式纯css修改
    vue 页面切换的时候vuex记录之前的滚动条位置
    vue从入门到进阶
    es6 学习笔记
    vue 项目笔记
  • 原文地址:https://www.cnblogs.com/xchaos/p/2577368.html
Copyright © 2011-2022 走看看