zoukankan      html  css  js  c++  java
  • zzuli新生周赛第四周题解

    A.Bananice

      将每一位上的4都单独计算。
      个位数上可出现的4的情况为:固定个位数的4,然后个数为其他位上出现的数的总和。eg:42564--->一共有4257(0-4256)个,同理42565-->4257,但是42563-->4256(0-4255)个。
      那么将上述情况推广到每一位上:
      将其中一位数定位4,假设是百位,样例n为42564, 相当于将4挖去,并且计算前面位数没到达极限的情况,即万位小于4或者万位等于4千位小于2的时候所有(固定了百位4)情况其他位取任何数都是可行的。一共4200种。然后开始计算固定前面位数为最极限状态,后面的位数出现的情况:

    • 当n中的该位为4时,可以取的数字就是后面位数可取范围+1(n=42465,后面位数可取66(0-->65)),如果是千位则是(n=44256-->257(0-256)。
    • 当n中该位为大于4时,可以取的数字为100(0-->99),求千位则是(0-->999)以此推类。
    • 当n中该为小于4时,没有满足条件。
    int main(){   
      ll n;scanf("%lld",&n);   
      ll count=0,num=1,m=n;
       while(n)   
      {
          count+=n/10*num;
          if(n%10>=5) count+=num;
          else if(n%10==4)
           count+=m%num+1;      
          num*=10;n/=10;
       }   
    printf("%lld
    ",count);
    }
    

    B.玄不救非,氪不改命

      sort为排序函数,而cmp函数为定义怎么排序。我们计算的答案在1-1e9内没被所有区间覆盖的长度。
      首先先按照l为基准从小到大排序。
      如果现在的rmax小于下一个的l,那么计算中间未被覆盖的的长度。然后维护现今最右边界。
      如果现在的rmaxn大于等于下一个l 那么中间没有未被覆盖的长度。但是依旧要维护最右边界。
      然后加上1到第一个l的未被覆盖的长度和rmax到1e9的未被覆盖长度。

    const int maxn=2e3+10;
    struct In
    {
        int l,r;
    }edge[100010];
    int cmp(struct In a,struct In b)
    {
        return a.l==b.l? a.r<b.r:a.l<b.l;
    }
    int main()
    {
       int n;scanf("%d",&n);
       for(int i=0;i<n;i++)
        scanf("%d%d",&edge[i].l,&edge[i].r);
       sort(edge,edge+n,cmp);
       ll ans=0;int maxx=edge[0].r;
       for(int i=1;i<n;i++)
       {
       	if(maxx<edge[i].l) ans+=edge[i].l-maxx;
       	maxx=max(maxx,edge[i].r);
       }
    
       ans+=edge[0].l+1e9-maxx;
       printf("%lld
    ",ans);
    }
    

    C.向着星辰与深渊,欢迎来到冒险家协会

      数太大,直接相乘会超long long,因为不需要详细的数,只需要分辨出谁大谁小。所以可以用对数乘,利用(lna+lnb=ln(a imes b)),可以比较。在判断相等时,注意精度。

    int main()
    {
        //freopen("in.txt","r",stdin);
    	//freopen("out.txt","w",stdout);
        int n,m,t;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            double a=0,b=0,num;
            for(int i=0;i<n;i++)
            {
                scanf("%lf",&num);
                a+=log(num);
            }
            for(int i=0;i<m;i++)
            {
                scanf("%lf",&num);
                b+=log(num);
            }
            if(fabs(a-b)<=1e-8)
                cout<<"lgc:玩什么原神,还不快点给我过来训练!"<<endl;
            else if(a<b)
                cout<<"zjl学姐nb"<<endl;
            else
                cout<<"sj学姐nb"<<endl;
        }
        return 0;
    }
    

    D.SG函数

       从左上角到右下角,一共要向右走m-1步,向下n-1步,那么如果n+m-2是偶数,那么是Bob走最后一步,否则就是Alice走最后一步。

    int main(){
        int n,m;
    scanf("%d %d",&n,&m);
        int ans=(n+m-2)%2;
        if(ans) printf("first win");
        else printf("second win");
    }
    

    E.皮皮虾快跑(这题是签到题咋写的人这么少)

      求1到n有几个数不包含4444,考虑到n最大仅1e6,可直接暴力判断。

    int solve(int num)
    {
        while(num)
        {
            if(num%10000==4444)
                return 1;
            num/=10;
        }
        return 0;
    }
    int main()
    {
        int n;
        while(scanf("%d
    ",&n)!=EOF)
        {
            int cnt=0;
            for(int i=0;i<=n;i++)
                if(solve(i))
                    cnt++;
            printf("%d
    ",n-cnt);
        }
        return 0;
    }
    

    F.接化发

      求1到n的数对k取模,为0,1,2,3……k-1的数的个数。直接从1到n循环,开个数组记录答案个数。

    int cnt[100005];
    int main()
    {
        int n,k;
        while(cin>>n>>k)
        {
            memset(cnt,0,sizeof(cnt));
            for(int i=0;i<=n;i++)
                cnt[i%k]++;
            for(int i=0;i<k;i++)
                printf("%d
    ",cnt[i]);
        }
        return 0;
    }
    

    G.一元二次函数

      分类讨论
      当a和b都等于0时,该函数为常数函数,输出l;
      当a等于0,b不等于0时,该函数为一元一次函数,根据b的正负输出l或r;
      当a不为0,该函数为一元二次函数,若a大于0,将l和r分别代入函数求出函数值,对比函数值,输出l或r;若a小于0,由数学知识可知,当x为(-frac{b}{2a})时,函数值最大。若(-frac{b}{2a})不在区间内,且位于区间右侧,则输出r,若位于区间左侧,输出l。若(-frac{b}{2a})位于区间内,将(-frac{b}{2a})向下取整赋值给整数变量x1,变量x2为x1+1(若(-frac{b}{2a})为1.9,显然2才是答案,但1.9向下取整为1,所以要注意这种情况),代入,对比函数值,输出x1或x2。

    int main()
    {
        ll a,b,c;
        while(cin>>a>>b>>c)
        {
            ll l,r;
            cin>>l>>r;
            if(a==0&&b==0)
            {
                cout<<l<<endl;
                continue;
            }
            else if(a==0)
          {
                if(b>0)
                    cout<<r<<endl;
                else
                    cout<<l<<endl;
            }
            else
            {
                if(a>0)
                {
                    ll y1=a*l*l+b*l+c,y2=a*r*r+b*r+c;
                    if(y1>=y2)
                        cout<<l<<endl;
                    else
                        cout<<r<<endl;
                }
                else
                {
                    ll ans=-9999999999999,index;
                    ll x1=-b/(2*a);
                    if(x1<=l)
                        cout<<l<<endl;
                    else
                    {
                        for(ll i=max(l,x1-1);i<=min(r,x1+1);i++)
                        {
                            if(a*i*i+b*i+c>ans)
                            {
                                ans=a*i*i+b*i+c;
                                index=i;
                            }
                        }
                        cout<<index<<endl;
                    }
                }
            }
        }
        return 0;
    }
    

    H.佐仓绫音的号哭

      此题是防ak题,不过用到的算法只是最基础的二分和贪心,主要还是考验同学们的思维能力。如果有同学不会二分的话,建议先去学习一下。
      首先要打败一个分身,我们必须使用一个力量不小于分身能力值的成员,在保证这个前提下,尽量使用耐力值比较大的成员。其实我们不必纠结选出哪个耐力值比较大的同学,这样的话题目的难度会加大,我们只要知道什么时候需要换人,什么时候不需要换人就行了。
      首先我们需要声明一个结构体数组来存储每个成员的力量和耐力,然后按每个成员的力量从小到大排序,因为我们是按力量的大小来排序的,那么这位成员以后的成员的力量自然也不小于当前分身的能力值。设当前的位置是i,我们再建立一个数组,用来存储从i到n中的所有成员中的最大的耐力值,然后在用一个变量days来存一下当前成员用掉的耐力值。这样,我们用二分快速查找出一个最小的力量不小于当前分身能力值的成员的下标i,于是我们就得到了一个解集,这个解集中的所有的成员力量都不小于当前分身的能力值,且他们最大的耐力值是k,对于下一个分身,如果我们当前解集中的成员的力量不够或者耐力值不够了,那么我们就需要继续向后查找了,这时候就有几种情况:
      1.力量最大的成员的力量小于某个分身,无解。
      2.力量够,耐力值够。肯定还能打,继续下一个分身。
      3.力量够,耐力值不够。这种情况我们这一天肯定是没法打了,只能下一天继续打,于是我们进行一次二分,然后更新现在解集的能力值和耐力值上限以及当前成员用掉的耐力值days,同时答案+1。
      4.力量不够,耐力值也不够。这种情况和上一种一样。
      5.力量不够,但是耐力值还够。这时候我们也需要二分再找一个成员,这个成员打败的分身数量将会继承上一个成员打败的分身数量,如果这个成员的耐力值不够打败那么多分身,那么之前的分身只能由前一天的成员来打,这个成员属于下一天,更新现在解集的能力值和耐力值以及days,同时答案+1。否则的话,只更新解集的能力值即可。

    const int maxn = 2e5+10;
    const int maxm = 2e2+10;
    struct IF {
        int x, cnt;
    } info[maxn], arr[maxn]; int post[maxn];
    int main() {
        int t; cin >> t;
        while(t--) {
            int n; cin >> n;
            for (int i = 1; i<=n; ++i) scanf("%d", &arr[i].x); 
            int m; cin >> m;
            for (int i = 1; i<=m; ++i) scanf("%d%d", &info[i].x, &info[i].cnt);
            sort(info+1, info+m+1, [](IF a, IF b) {return a.x<b.x;});
            post[m+1] = 0;
            for (int i = m; i>=1; --i) post[i] = max(post[i+1], info[i].cnt);
            int damage = 0, cnt = 0, days = 0, ans = 0;
            for (int i = 1; i<=n; ++i) {
                ++cnt;
                if (days<cnt || damage<arr[i].x) {
                    int p = lower_bound(info+1, info+m+1, arr[i], [](const IF &a, const IF &b) {return a.x<b.x;})-info;
                    if (p==m+1) {
                        cout << -1 << endl; goto out;
                    }
                    if (days<cnt) ++ans, cnt = 1;
                    days = post[p], damage = info[p].x;
                    if (days<cnt) ++ans, cnt = 1;
                }
            }
            cout << ans << endl;
            out:;
        }
        return 0;   
    }
    

    I. 末日时在做什么?有没有空?可以来拯救吗?

      略过,不会写。

    J.zjl姐姐的微笑

      求极限的公式相当于求一个无限大的矩形能放粉色气球的最大比例。我们可以用下图中的放置方法来铺满整个矩形
    ,对于处于非边界区域的位置,显然有2/3的地方可以放置粉色气球,而对于边界区域的位置,则可放置的数量会少于2/3,但是我们的矩形是无限大的,所以当n和m趋近于正无穷的时候,答案就是2/3。题目要保留20为有效数字,自然不能写分数,那就只能是小数,但是因为double的有效位数不够用,所以直接输出3.0/2.0也是不对的,可以用字符串输出答案,即

        printf("0.66666666666666666667
    ");
    
  • 相关阅读:
    洛谷P1182 数列分段`Section II`
    洛谷P3902 递增
    洛谷P1678-烦恼的高考志愿
    POJ 3263-Tallest Cow
    洛谷P2280 [HNOI2003]激光炸弹
    POJ 1958
    Vijos 1197
    VirtualBox 导入.vdi文件时报“uuid is exists”错误
    解压常用
    cut 命令
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/14021488.html
Copyright © 2011-2022 走看看