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\n", 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;
}

 

转载于:https://www.cnblogs.com/DWVictor/p/11357356.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值