Codeforces Round #339 (Div. 2)

来源:互联网 发布:丰臣秀吉大明朝知乎 编辑:程序博客网 时间:2024/06/01 22:33

题目链接:http://codeforces.com/contest/614


CodeForces - 614A

题意:给定l,r,k。输出k^0,k^1,k^2....k^n在[l,r]这个范围里面的数,如果没有这样的数则输出-1

思路:暴力,注意精度,因为r为10^18次方,如果是num>r再结束的话会溢出,应该是num>r/k就要退出了

#define _CRT_SECURE_NO_DEPRECATE#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<stdlib.h>using namespace std;#define INF 0x3f3f3f3ftypedef long long int LL;int main(){LL l,r, k;while (scanf("%I64d%I64d%I64d",&l,&r,&k)!=EOF){LL num = 1; bool flag = false;//flag判断数字是否又在[l,r]内while (1){if (num >= l&&num <= r)//在范围里{flag = true;printf("%I64d ", num);}if (num > r/k +1)//下次再乘就已经超出了,则退出{//注意是下次乘才超出,本次是不超出的,防止溢出break;}num *= k;}if (!flag){printf("-1\n");}else{printf("\n");}}return 0;}

CodeForces - 614B
题意:给定n个没有前导0的整数,并且保证至少有n-1个完美数,所谓完美数:数字只有0和1组成。
并且1的个数最多只有1个,输出这n个数的乘积,所以数字的长度小于 100000.
思路:模拟,因为数字很大所以要用字符串。一共分3种情况:
 1:n个数字中有0.【结果是0】
 2:n个数字没有0,并且刚好有n-1个完美数【找出非完美数,然后统计n-1个完美数的后缀'0'的个数, 结果为非完美数+‘0’的个数】
 3:n个数组没有0,并且n个都是完美数【即都是10的次方的数,则结果为'1'+n个数的后缀'0'的个数】

#define _CRT_SECURE_NO_DEPRECATE#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<stdlib.h>#include<stack>using namespace std;#define INF 0x3f3f3f3fconst int MAXN = 100005;typedef long long int LL;char num[MAXN],unbty[MAXN];int beautiful(char *m)//判断数组m是不是完美数{//若是非完美数返回-1,若是完美数返回后缀‘0’的个数int total_one =0;//1的个数int total_zero = 0;//0的个数for (int i = 0; i < strlen(m);i++){if (m[i] != '0' && m[i] != '1')//数字包含非0和1,不是完美数{return -1;}if (m[i] == '1')//出现1{total_one++;}else{//后缀0total_zero++;}if (total_one >= 2)//1的个数大于1个,非完美数{return -1;}}return total_zero;//返回后缀0的个数}int main(){int n;while (scanf("%d",&n)!=EOF){int total=0;//n个数的后缀0个数int flag=2;//3种状态 0:包含0 1:刚好有一个非完美数 2:没有非完美数,即n个都是完美数for (int i = 0; i < n; i++){scanf("%s", num);if (num[0] == '0'&&strlen(num)==1)//数字长度为1,并且字符是0,即出现了0{flag = 0;}int tt = beautiful(num);if (tt == -1&&flag)//出现非完美数,并且没有出现0{strcpy(unbty, num);//将非完美数复制下来flag = 1;}else{total += tt;//否则是完美数,累加后缀0}}if (flag==0){printf("0\n");}else{if (flag == 1){printf("%s", unbty);}else//状态=2,即n个都是完美数{printf("1");}for (int i = 0; i < total; i++)//后缀0{printf("%c", '0');}printf("\n");}}return 0;}

CodeForces - 614C
题意:给定一个n边形的坐标(输入保证坐标按逆时针或者顺时针排序),然后给定一个点P。问这个多边形绕点P选中后得到的图形的面积。
思路:计算几何,从样例图可以做到,面积肯定是大圆面积-小圆面积。接下来问题就变成了求大圆和小圆的半径,大圆半径=点P到多边形的最大距离,小圆半径=点P到多边形的最短距离。注意这些距离不一样是点P到多边形的顶点距离,也可能是点P到多边形边的距离。所以模板搞一搞就行

#define _CRT_SECURE_NO_DEPRECATE#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<stdlib.h>using namespace std;#define INF  0x3f3f3f3fconst double EP = 1E-10;const double PI = 3.14159265;const int MAXN = 100005;typedef long long int LL;struct POINT{double x;double y;POINT(double a = 0, double b = 0) { x = a; y = b; } //constructor }p[MAXN];struct LINESEG{POINT s;POINT e;LINESEG(POINT a, POINT b) { s = a; e = b; }LINESEG() { }};double multiply(POINT sp, POINT ep, POINT op){return((sp.x - op.x)*(ep.y - op.y) - (ep.x - op.x)*(sp.y - op.y));}double dotmultiply(POINT p1, POINT p2, POINT p0){return ((p1.x - p0.x)*(p2.x - p0.x) + (p1.y - p0.y)*(p2.y - p0.y));}double dist(POINT p1, POINT p2)                // 返回两点之间欧氏距离 {return(sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)));}double relation(POINT p, LINESEG l){LINESEG tl;tl.s = l.s;tl.e = p;return dotmultiply(tl.e, l.e, l.s) / (dist(l.s, l.e)*dist(l.s, l.e));}// 求点C到线段AB所在直线的垂足 P POINT perpendicular(POINT p, LINESEG l){double r = relation(p, l);POINT tp;tp.x = l.s.x + r*(l.e.x - l.s.x);tp.y = l.s.y + r*(l.e.y - l.s.y);return tp;}/* 求点p到线段l的最短距离,并返回线段上距该点最近的点np注意:np是线段l上到点p最近的点,不一定是垂足 */double ptolinesegdist(POINT p, LINESEG l){POINT np;double r = relation(p, l);if (r<0){np = l.s;return dist(p, l.s);}if (r>1){np = l.e;return dist(p, l.e);}np = perpendicular(p, l);return dist(p, np);}int main(){int n; POINT P;while (scanf("%d %lf %lf",&n,&P.x,&P.y)!=EOF){double mindist = INF, maxdist = -1;//大圆半径,小圆半径for (int i = 0; i < n; i++)//先求到顶点的距离{scanf("%lf %lf", &p[i].x, &p[i].y);mindist = min(mindist, dist(P, p[i]));maxdist = max(maxdist, dist(P, p[i]));}p[n] = p[0]; for (int i = 0; i < n; i++)//再求到边的距离{mindist = min(mindist, ptolinesegdist(P, LINESEG(p[i], p[i + 1])));maxdist = max(maxdist, ptolinesegdist(P, LINESEG(p[i], p[i + 1])));}double ans = PI*maxdist*maxdist - PI*mindist*mindist;//结果printf("%.10lf\n", ans);}return 0;}

CodeForces - 614D
题意:给定n个技能,技能的最大值为A。现有技能点m,每个技能点能让一个技能上升一级【不能超过最大值】每个玩家的积分为:技能满的个数*cf+技能的最小值*cm。求输出积分的最大值和对应的n个技能的分配技能点后的情况。
思路:首先特判如果现有技能点m能让所以技能都升满,那么直接可以得出结果。否则。预处理技能的前缀和。然后枚举让技能点满的个数为i(0<=i<=n)时,剩下的技能点最多能使整体技能最小值提升到多少,然后判断取积分最大的情况可以用二分求剩下的技能点最多能使整体技能最小值提升到多少。简单来说就是优先让技能高的先点满,然后剩下的技能点让整体的最小值尽可能的增大
补充:代码迷之WA26.改不动了,估计是二分那里出错了。

#define _CRT_SECURE_NO_DEPRECATE#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<stdlib.h>using namespace std;#define INF  0x3f3f3f3fconst int MAXN = 100005;typedef long long int LL;struct Node//技能{LL val;//等级int id;//是第几个技能}a[MAXN];LL tmp_a[MAXN],sum[MAXN];//技能副本【排序后,用于二分】,前缀和【用于求需要的技能点】int n;  LL A, cf, cm, m;//题目输入bool cmp(Node a, Node b)//降序排序{return a.val < b.val;}bool Return(Node a, Node b)//恢复位置{return a.id < b.id;}bool C(LL val, LL Residual)//剩下的点数Residual能否使最小值为val{int index = 0; LL needval;index = lower_bound(tmp_a + 1, tmp_a + 1 + n, val) - (tmp_a + 1);needval = LL(index*val) - sum[index];if (Residual >= needval){return true;}else{return false;}}int main(){while (scanf("%d %I64d %I64d %I64d %I64d",&n,&A,&cf,&cm,&m)!=EOF){LL total = 0,maxnum=0;//让所有技能点满所需的技能点, 技能满的个数for (int i = 1; i <= n; i++){scanf("%I64d", &a[i].val);if (a[i].val == A)//技能满的个数{maxnum++;}a[i].id = i;total += A - a[i].val;//累加让每个技能点满所需的技能点个数}if (m >= total)//拥有技能点能让所有技能点满{printf("%I64d\n", A*cm + n*cf);for (int i = 1; i <= n; i++){printf("%I64d ", A);}printf("\n");}else{sort(a + 1, a + n + 1, cmp); sum[0] = 0;//排序for (int i = 0; i <= n; i++)//初始化副本{tmp_a[i] = a[i].val;}for (int i = 1; i <= n; i++)//预处理前缀和{sum[i] = sum[i - 1] + a[i].val;}LL total_A = 0, minval = a[1].val, tmp_max = maxnum*cf + minval*cm;//最优案例时:满技能的个数,整体技能的最小值,此时的积分for (LL i = 0; i <= n; i++)//让i个技能点满{LL tmp_m = m - (LL(i*A) - (sum[n] - sum[n - i]));//剩下的技能点if (tmp_m < 0){continue;}else//二分能分配的最小值是多少{LL l = 0, r = A, mid;while (r>=l){mid = (l + r ) >> 1;if (C(mid,tmp_m)){l = mid+1;}else{r = mid-1;}}if (LL(i*cf) + LL(r*cm) > tmp_max)//此样例的积分{tmp_max = LL(i*cf) + LL(r*cm);minval = r;//保存当前最优的最小值total_A = i;//保存当前最优的满技能个数}}}for (int i = 0; i < total_A; i++)//让total_A个技能点满,优先让技能高的先点满{a[n - i].val = A;}for (int i = 1; i <= n; i++)//技能等级小于最优的最小值的技能都升到最优的最小值{if (a[i].val < minval){a[i].val = minval;}else{break;}}sort(a + 1, a + n + 1, Return);//恢复技能位置printf("%I64d\n", tmp_max);for (int i = 1; i <= n; i++){printf("%I64d ", a[i].val);}printf("\n");}}return 0;}


0 0
原创粉丝点击