• 8.15早训有意思的题


    B - Mister B and Angle in Polygon

     CodeForces - 820B 

    计算几何

    题意

    输入n个点,创建一个正n边形,把每个点之间都连起来(如下图举例所示),求出最接近所给∠a的角的角的三个顶点a,b,c,其中b为顶点。

    题解

    先说下这题的思路,这题并不是难在代码,但是不太好想。正n边形的内角和为 (n-2)*180°,这个公式当时自然记得。
    但是,有些别的点却是要自己想的,简述思路如下:
    正n边形每个顶角的大小为 (n-2)*180/n°
    对正n边形的任一顶点,除去它自己和相邻的两个顶点,该定顶点可以与剩余的 (n-3) 个顶点连成(n-3)条对角线,这些对角线可将该顶点对应的顶角分为(n-3)+1,即(n-2)个部分,每部分180/n°
    
    于是正n边形任意三个顶点构成的角度的范围,则是从 180/n° ~ 180 * (n-2) /n°
    为了方便输出,许多博客上的题解,都是采用固定前两个顶点,例如固定2 1,因为这样固定,目标答案所对应的角度,和第三个顶点的序号的的关系,比较容易能表示出来
    
    #include <bits/stdc++.h>
    using namespace std;
    int main(int argc, char const *argv[])
    {
        int n , a;
        cin >> n >> a;
        double tmp = 180.0 * (n - 2) / n ;
        double ang = (180.0 - tmp) / 2;
        double angs = ang;
        int id = 3; 
        for(int i = 4;i <= n;i ++){
            double ans = 1.0 * ang * (i - 2);
            if(abs(angs - a) > abs(ans - a)){
                angs = ans;
                id = i;
            }
        }
        cout << "2 1 " << id <<endl;
        return 0;
    }

    C - Mister B and PR Shifts

     CodeForces - 820D 

    用cnt数组记录当前num[i]所在位置 到 下标为num[i]的位置 需要向右循环移位几次,两个变量add、sub表示下一次移位会使sum值+1/-1的个数,每次更新均在上一排列的基础上进行。

    先注意题意, 1 <= num[i] <= n。

    再注意一点,对于每个位置的数,设为num[i],先不看num[i] = 0或者num[i] = n的情况,对于其他情况,从1到num[i]这段区间,num[i]右移使|num[i] - loc|单减,从num[i]到n这段区间,num[i]右移使|num[i] - loc|单增;对于num[i] = 0,从1到n,|num[i] - loc|一直单增;对于num[i] = n,num[i]右移使|num[i] - loc|单减;当num[i]从n移动到1,增减不一定。所以对于每个数num[i],位置num[i]是个转折点,决定下一步|num[i] - loc|如何变化(每次+1还是-1)。具体思路见注释。

    // CodeForces 820D Mister B and PR Shifts 运行/限制:264ms/2000ms
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define LL long long
    int num[1000005],cnt[1000005];
    int main(){
        int n;
        int add, sub, index;
        LL sum, re;
        while (scanf("%d", &n) != EOF) {
            sum = 0; add = 0; sub = 0;
            memset(cnt, 0, sizeof(cnt));
            for (int i = 1; i <= n; i++) {
                scanf("%d", &num[i]);
                sum += fabs(num[i] - i);
                cnt[(num[i] - i + n) % n]++;//cnt下标为:当前num[i]所在位置 到 num[i]位置 需要移位几次
                if (num[i] > i) sub++;//下一次移位会使值-1的个数
                else add++;//下一次移位会使值+1的个数
            }
            re = sum; index = 0;
            for (int i = 1; i < n; i++) {//每次在前一次移位的基础上处理,i为第几次移动
                sum += add - sub - 1;//当前最后一位肯定满足数值小于等于n(数据范围最大是n),所以之前计算在add里了;但因为要移动到首位,所以不一定是加、减
                sum += (num[n - i + 1] - 1) - (n - num[n - i + 1]);//计算当前最后一位移动到首位sum值的变化;
                                                                   //每次并没有真正进行移位,而是每次计算最后一位应该是未移位序列的哪个位置了
     
                //求完sum,相当于该次移动了
     
                //根据此次移动后的结果,更新下一步add、sub会出现的值
                //-1,+1是因为这一次移动后到第一个位置的数,由于单调性反转,使add比正常情况-1、sub+1。
                //num[i] = 1时,|num[i] - loc|全程单调递增,从n位置移动到1位置时单调性的变化是个特例,可以分析一下num[n] = 1也满足下面式子
                add = add + cnt[i] - 1;
                sub = sub - cnt[i] + 1;
                if (sum < re) {
                    re = sum;
                    index = i;
                }
            }
            printf("%lld %d
    ", re, index);
        }
        return 0;
    }

    E - Okabe and Banana Trees

     CodeForces - 821B 

    枚举Y,等差数列求和

    #include <bits/stdc++.h>
    using namespace std;
    int main(int argc, char const *argv[])
    {
        // y = -x/m + b
        long long m , b ;
        cin >> m >> b;
        long long maxx = 0;
        for(int i = b;i >= 0;i --){
            long long sum = 0;
            long long border = m * (b - i);
            sum=((border+1)*border/2)*(i+1)+(i*(i+1)/2)*(border+1);
            if(sum > maxx) maxx = sum;
        }
        cout << maxx << endl;
        return 0;
    }

    F - Okabe and Boxes

     CodeForces - 821C

    思维,vector 模拟一下,点 : 不满足排序 == 清空vector 

    #include <bits/stdc++.h>
    using namespace std;
    std::vector<int> v;
    int main(int argc, char const *argv[])
    {
        int n ;
        cin >> n ;
        int cnt = 0,ans = 0;
        string str;
        while(cin >> str){
            //cnt ++;
            if(str[0] == 'a'){
                int x;cin >> x;
                v.push_back(x);
            }else{
                cnt++;
                if(!v.empty())
                if(v.back() == cnt) v.pop_back();
                else v.clear(),ans++;
            }
        }
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    20200213 超级聊天术
    20220210 java.util.Properties
    20220210 java.util.concurrent.BlockingQueue 方法说明
    20220210 java.util.Queue
    20220210 java.lang.Long
    20220210 Java 反射基础类
    一组很有意思的Principles
    python logging用法的简单总结
    好好的Typora收费了!_2022_01_20
    一些常用的jQuery方法1_20220128
  • 原文地址:https://www.cnblogs.com/DWVictor/p/11357356.html
Copyright © 2020-2023  润新知