Codeforces Round #339 (Div. 2) (A,B,C,D)

Codeforces Round #339 (Div. 2) (A,B,C,D)

tags : Codeforces


这场写得我心好累。昨天早上虚拟的时候两个小时才搞定两题,第三题就写了个漏洞百出的版本不过没交上去。昨天下午补了C题,结果被D题坑了快一天,今天下午才好不容易AC,感觉整个人都不好了。。。╮(╯_╰)╭所以我决定这份题解描述题意的时候尽量简化一下

A.Link/Cut Tree

题意

输出[l,r]范围内k的倍数

解析

暴力即可,只需注意防中间运算爆long long

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>

using namespace std;

#define MAXN    100000+100

long long l, r,k;

int main()
{
    scanf("%lld%lld%lld",&l,&r,&k);
    long long p = 1;
    int first = 1; 
    while (p<=r)
    {
        if (p >= l)
        {
            if (!first)
                printf(" ");
            printf("%lld",p);
            first = 0;
        }
        if ((r*1.0 / p) < k)
            break;
        p *= k;
    }
    if (first)
        printf("-1\n");
    else
        printf("\n");
    return 0;
}

B.Gena’s Code

题意

求n个数相乘的结果。

解析

数字超级大,不能直接相乘,需要以字符串方式处理。
题目讲得很明白了,最多只有一个不是10的倍数,只要找到这个数,然后作为前缀,其他数字只考虑是10的多少次(即,字符串长度-1),求和得到相乘后0的个数k(不考虑前缀中的0)。
输出时先输出前缀,再输出k个0即可。

注意,前缀可能为0,此时不用再输出0。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>

using namespace std;

#define MAXN    100000+100

char str[MAXN];

int check(int l)
{
    if (l == 1 && str[0] > '1')
        return 1;
    int cnt = 0;
    for (int i = 0; i < l; i++)
    {
        if (str[i] > '1')
            return 1;
        else if (str[i] == '1')
        {
            cnt++;
            if (cnt > 1)
                return 1;
        }
    }
    return 0;
}

int main()
{
    int n;
    scanf("%d",&n);
    char head[MAXN]="1";
    int len = 0;
    for (int i = 0; i < n; i++)
    {
        int k;
        scanf("%s",str);
        int slen = strlen(str);
        if (str[0] == '0' && slen == 1)
        {
            strcpy(head,str);
            break;
        }
        if (check(slen))
        {
            strcpy(head, str);
        }
        else
        {
            len += slen-1;
        }
    }
    printf("%s", head);
    if (head[0] != '0')
    {
        for (int i = 0; i < len; i++)
            printf("0");
    }
    printf("\n");
    return 0;
}

C.Peter and Snow Blower

题意

求多边形绕点P旋转扫过的面积。

解析

主要就是求内半径和外半径
显而易见,外半径就是P点到多边形顶点的最大距离。遍历即可求出。
而内半径,是P点到多边形边上点的最小距离。抄一份点到线段的最短距离代码即可算出。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>

using namespace std;

#define PI      3.1415926535897932384626
#define MAXN    100000+100

const double esp = 1e-7;


double dis(double x1, double y1, double x2, double y2)
{
    return sqrt((x1 - x2*1.0)*(x1 - x2*1.0) + (y1 - y2*1.0)*(y1 - y2*1.0));
}

struct node
{
    double x, y;
    node(){};
    node(double xx, double yy)
    {
        x = xx;
        y = yy;
    }
}p[MAXN];

double Dot(node a, node b) //点积
{
    return a.x*b.x + a.y*b.y;
}

double Length(node a) { return sqrt(Dot(a, a)); }

double dis2line(node a, node b, node c)
{

    node v1, v2, v3;
    v1.x = c.x - b.x;
    v1.y = c.y - b.y;
    v2.x = a.x - b.x;
    v2.y = a.y - b.y;
    v3.x = a.x - c.x;
    v3.y = a.y - c.y;
    if (Dot(v1, v2)<0) return Length(v2);
    else if (Dot(v1, v3)>0) return Length(v3);
    else return fabs((v1.x*v2.y - v2.x*v1.y) / Length(v1));
}

int main()
{
    int n;
    double px, py;
    double mindis = -1;
    double maxdis = -1;
    scanf("%d%lf%lf", &n, &px, &py);
    for (int i = 0; i < n; i++)
    {
        double x, y;
        scanf("%lf%lf", &x, &y);
        p[i].x = x;
        p[i].y = y;
        double dist = dis(p[i].x, p[i].y, px*1.0, py*1.0);
        if (maxdis < 0 || dist > maxdis)
            maxdis = dist;
        if (mindis <0 || dist  < mindis)
            mindis = dist;
        if (i >  0)
        {
            dist = dis2line(node(px, py), node(x, y), node(p[i - 1].x, p[i - 1].y));
            if (maxdis <0 || dist > maxdis)
                maxdis = dist;
            if (mindis <0 || dist < mindis)
                mindis = dist;
        }
    }
    double dist = dis2line(node(px, py),node(p[0].x, p[0].y), node(p[n - 1].x, p[n - 1].y));
    if (maxdis < 0 || dist > maxdis)
        maxdis = dist;
    if (mindis < 0 || dist< mindis)
        mindis = dist;
    printf("%.8lf\n", (maxdis*maxdis*PI - mindis*mindis*PI));
    return 0;
}

D.Skills

这题坑了我整整一天啊fuck,,,简直是知道做法还是做不出来的典范啊艹。用逗比的话来说就是,“明明知道做法但是姿势怎么摆都不对”

题意

一共n个技能,最大等级都为A,当前等级已给出。现在有m个技能点,需要通过这些技能点使“战斗力”最大化
战斗力=满级技能数*Cf + 最低技能等级*Cm

输出最大化的战斗力和对应的技能等级。

解析

先将所有技能位置和等级记录下来,然后按等级排序。然后进行预处理,求出后缀和sum[i]
显然能做的操作有两种:1.将当前等级最高的技能提升至满级,2.将当前等级最低的技能提升至一定等级。操作时先1后2相对简便很多。
我们可以枚举满级技能的数目full,减去消耗掉的i*A - (sum[0] - sum[i])后,剩下的技能点为mm,然后每次迭代去计算使用mm点的技能点能将技能最低等级提升至多少。如何计算呢?我们可以通过二分查找,找到[i,n-1]范围内第一个满足min(A, (sum[mid] + mm) / (n - mid)) >= arr[mid].v的点(其值记为minv)。也就是说,将mm加到从当前位置mid开始到最后的技能上,使其等级全部提升至min(A, (sum[mid] + mm),假如这个值大于或等于arr[mid].v,说明mm够用;反之,若小于arr[mid].v,说明mm不够用,应当考虑将mid后移。
每次迭代得到一个fullminv从而计算出对应的战斗力fnow,记下fnow的最大值及对应的fullminv值。
得到最大时的fullminv值后,很容易就能将技能提升为最终的等级。最后重新按序号排序即可。

实际上有一种更快一点的方法,就是按满级技能数full从大到小进行处理,可以将复杂度压缩一点(虽然差距并不大)。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>

using namespace std;

#define MAXN    100000+100

struct node
{
    int index;
    long long v;
}arr[MAXN];

bool cmpi(node a, node b)
{
    return a.index < b.index;
}

bool cmpv(node a, node b)
{
    return a.v > b.v;
}

long long sum[MAXN];

int main()
{
    int n;
    long long cf, cm, m, A;
    scanf("%d%lld%lld%lld%lld", &n, &A, &cf, &cm, &m);
    for (int i = 0; i < n; i++)
    {
        scanf("%lld", &arr[i].v);
        arr[i].index = i;
    }
    sort(arr, arr + n, cmpv);

    sum[n] = 0;
    for (int i = n - 1; i >= 0; i--)
    {
        sum[i] = sum[i + 1] + arr[i].v;
    }
    m = min(A*n - sum[0], m);
    long long s = 0;
    long long full = 0;
    long long minv = 0;
    long long maxf = 0;
    for (int i = 0; i < n; i++)
    {
        long long mm;
        if (i == 0)
            mm = m;
        else
            mm = m - (i*A - (sum[0] - sum[i]));
        if (mm < 0)
            break;
        long long avg = min(A, (sum[i] + mm) / (n - i));
        long long l = i,r=n-1;
        while (l<r)
        {
            long long mid = (l + r) / 2;
            avg = min(A, (sum[mid] + mm) / (n - mid));
            if (avg >= arr[mid].v)
                r = mid;
            else
                l = mid+1;
        }
        avg= min(A, (sum[r] + mm) / (n - r));
        if (i == 0)
        {
            if (avg == A)
            {
                maxf = cf*n + cm*avg;
                minv = avg;
                full = n;
            }
            else
            {
                maxf = cm*avg;
                minv = avg;
                full = 0;
            }
        }
        else
        {
            long long fnow = i*cf + avg*cm;
            if (fnow > maxf)
            {
                maxf = fnow;
                minv = avg;
                full = i;
            }
        }
    }
    printf("%lld\n", maxf);
    for (int i = 0; i < n; i++)
    {
        if (i < full)
            arr[i].v = A;
        if (arr[i].v < minv)
            arr[i].v = minv;
    }
    sort(arr, arr + n, cmpi);
    int first = 1;
    for (int i = 0; i < n; i++)
    {
        if (!first)
            printf(" ");
        printf("%lld", arr[i].v);
        first = 0;
    }
    printf("\n");
    return 0;
}

竟然有转载还不附上原地址的?为了测试对方是不是爬虫我决定加上这一段

原文在CSDN上,链接http://blog.csdn.net/lincifer/article/details/50534579

还有我那连域名都还没有的博客上也有一份,链接http://115.28.240.133:8080/archives/85

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值