B - Mister B and Angle in Polygon
计算几何
题意
输入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
用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
枚举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
思维,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; }