CTU Open Contest 2019 计蒜客重现——总结

个人总结

寒假过完的第一场比赛,总是有很多问题。主要有以下两点:一是寒假做题有点依赖翻译,看不下去很长的英文题面,导致这次比赛的一些题目看很长时间也没看懂。二是发现了自己的做题量仍然很少,很多题目缺乏练习导致即使知道这些知识点,会写会用,但是总是倒在一些坑点或者数据范围上。比如A题卡了我三个小时,红了十几发,最后竟然是组合数的杨辉三角做法,数组没开long long导致溢出的。我以前只注意杨辉三角的计算范围是1000以内的组合数,因为当时有取模运算,所以开了int数组也过了,如今很多题目的数据范围都给的很大,所以很多时候要注意开long long。当然这套题也还有不足的地方,我记得B题一个输出样例是错的,结束后才发现又改了过来,我说这个模拟题怎么实际输出和题目描述的输出有矛盾。尽管学了一个寒假,但是一两次比赛看不出来自己的进步。由于ICPC的知识点涉及仍然非常广,所以只有不畏艰难和失败,坚持攀登的人才有希望达到光辉的终点

Beer Barrels

题目链接

Finally, you got into the cellar of your preferred brewery where you expected many large piles ofbeer barrels to be stored. You are eager to inspect the barrels and maybe even their content (alot and lot of content, actually…). Unfortunately, you find only five barrels, all hopelessly emptyand dry. Some numbers are painted on the fifirst four barrels, one number on each of them. Anote is attached to the fififth barrel. Behind the barrels in the dark, there is some low and barelydiscernible door in the wall, leading quite obviously to another lower cellar where you hope awhole slew of full barrels is kept hidden. The door is locked with a heavy and complex lookinglock. With no obvious further constructive action in mind, you sit down to study the note onthe fififth barrel. Its essence is the following. Denote the numbers painted on the fifirst, second, third and fourth barrel by A, B, K and C.Numbers A, B and C are just single digits. Now imagine that in the distant future some incredibly powerful computer (powered by quantumyeast) prints a list of all numbers which have exactly K digits and in which each digit is equalto A or B. Another equally mighty computer then takes the list and also the value C as theinput and calculates the number of occurrences of digit C in the whole list. The resulting number taken modulo 1 000 000 007 is to be typed into the door lock to open itand to gain access to the lower cellar. You decide to calculate that number in your notebook you took with you.

Input Specifification

The input consists of a single line with four integers A, B, K, C (1 ≤ A, B, C ≤ 9, 0 ≤ K ≤ 1000)which represent the numbers painted on the fifirst four barrels.

Output Specifification

Output a single integer which opens the door lock.

1.题目大意:有A,B,K,C四个数字,现在要求长度为K且仅包含A或B的数字排列中,C数字出现了多少次。结果对1e9+7取模

2.很明显,一共有四种情况:一是如果C不等于A也不等于B,那么结果肯定是0;二是如果K等于0,显然结果也是0;三是C既等于A又等于B,那么显然数字排列只有一种,且结果是K;四是一般情况,C等于A,B其中一个且A≠B。由于无论等于A还是等于B结果一样,我们就先设C=A。那么我们先把K个数字写成待填充的圆圈,假如只有一个A,可选择插入的位置有K个,其他都插入B,那么一共有K种。然后假如排列中有两个A,那么就是这两个A任意选择两个位置插入,其他全是B,一共有2*C(K,2)种,以此类推,实际上就是组合数的一个公式,最后的结果是1*C(K,1)+2*C(K,2)+…+K*C(K,K)

#include <iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll P=1e9+7;  //开ll
ll C[1005][1005];  //开ll
ll ans=0;
int a,b,k,c;

void init(){  //杨辉三角
    C[0][0]=1;
    for(int i=1;i<=1002;i++){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<=(i>>1);j++){
            C[i][j]=C[i][i-j]=(C[i-1][j]+C[i-1][j-1])%P;
        }
    }
}

int main()
{
    init();
    scanf("%d%d%d%d",&a,&b,&k,&c);
    if(c!=a && c!=b){
       printf("0\n");
    }
    else if(a==b){
       printf("%d\n",k);
    }
    else{
       for(int i=1;i<=k;i++){
           ans=(ans%P+(i*C[k][i])%P)%P;
       }
       printf("%lld\n",ans);
    }
    return 0;
}

Beer Bill

题目链接

1.题目大意:计算字符串的价格。给多个字符串,每个串占一行。字符串分两种,一种字符串名为 Raked Line 只含有 C 个’|字符,这种字符串的价格定义为 42C。另一种字符串名为 Priced Line,格式是以数字 price 开头、中间用两个字符“,-“连接,结尾是连续 C 个‘|’。,这种字符串的价格定义为 priceC,若结尾没有‘|’出现,则 C 默认为 1 个。计算所有字符串的总价,总价向上取整到 10 的倍数

2.两种字符串的价格很容易计算,可以直接统计‘|’个数再乘 42。第二种 Priced Line 可以先将开头的 price 字符串转整数,然后记录‘|’的个数,二者相乘得这一字符串的价格。注意当‘|’不出现时需要特殊处理一下。模拟题而已

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

string s;
int main()
{
    int ans=0;
    while(getline(cin,s)){
        int flag=0;
        if(isdigit(s[0])) flag=1;
        if(flag){
            int res=0,num=0;
            for(int i=0;i<s.size();i++){
                if(isdigit(s[i])) res=s[i]-'0'+res*10;
                else if(s[i]=='|') num++;
            }
            if(!num) num=1;
            ans+=res*num;
        }else{
            int num=0;
            for(int i=0;i<s.size();i++) num++;
            ans+=42*num;
        }
    }
    if(ans%10) ans+=10-ans%10;
    printf("%d,-\n",ans);
    return 0;
}

Beer Coasters

题目链接

Often, in an average pub, the beer is served in a mug which is, quite obviously, wet from inside,but also wet from outside. The barkeeper typically has no capacity to dry freshly washedmugs. To protect the table and the (optional!) tablecloth, beer coasters are used in mostpubs. Originally, the beer coasters were round, nowadays you can fifind a variety of difffferentshapes. Despite being perceived as slightly unorthodox, square and even rectangular coastersare manufactured and used daily in many self-respecting restaurants, taverns, beer houses anddrinkeries of high and low profifiles.A research related to the well-known satiric Ig Nobel Prize is being conducted in local pubs.The research aims to measure the rate of wear of the rectangular coasters. The rate of weardepends also on how much a coaster is getting wet from the contact with the wet bottom of beermugs. That, in turn, depends on the exact area of contact between the mug and the coaster.The exact position of the coaster and the mug on the table is recorded each time the mug is puton the coaster.Manysophisticatedcalculationsintheresearchtakeasinputtheareaofcontact,whichhastobecalculatedbyasuitablecomputerprogram.Youaretowritesuchaprogram.

Input Specification
The input contains 7 space-separated integers on a single line. The fifirst three integers X, Y , R describe the coordinates of the beer mug bottom on the table. The center of the mug bottom is at (X, Y ) and the radius of the mug bottom is R. The next four integers Ax, Ay, Bx, By describe the coordinates of two opposite corners, (Ax, Ay) and (Bx, By), of the coaster on the table. The coaster is a rectangle placed with its sides parallel to the coordinate axes. All coordinates are in the range from m 1000 to 1000, the radius is in the range from 1 to 1000. The radius and the coordinates are expressed in the same units of length.

Output Specifification
Output a single decimal number with precision of 4 digits after the decimal point, the area of contact between the coaster and the beer mug.

1.给出一个圆和矩形,求相交的面积

2.板子题,有篇博客写的很详细,借代码一用

#include<bits/stdc++.h>
#define inf 1000000000000
#define M 100009
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
struct Point
{
    double x,y;
    Point(){}
    Point(double xx,double yy){x=xx;y=yy;}
    Point operator -(Point s){return Point(x-s.x,y-s.y);}
    Point operator +(Point s){return Point(x+s.x,y+s.y);}
    double operator *(Point s){return x*s.x+y*s.y;}
    double operator ^(Point s){return x*s.y-y*s.x;}
}p[M];
double max(double a,double b){return a>b?a:b;}
double min(double a,double b){return a<b?a:b;}
double len(Point a){return sqrt(a*a);}
double dis(Point a,Point b){return len(b-a);}//两点之间的距离
double cross(Point a,Point b,Point c)//叉乘
{
    return (b-a)^(c-a);
}
double dot(Point a,Point b,Point c)//点乘 
{
    return (b-a)*(c-a);
}
int judge(Point a,Point b,Point c)//判断c是否在ab线段上(前提是c在直线ab上)
{
    if (c.x>=min(a.x,b.x)
       &&c.x<=max(a.x,b.x)
       &&c.y>=min(a.y,b.y)
       &&c.y<=max(a.y,b.y)) return 1;
    return 0;
}
double area(Point b,Point c,double r)
{
    Point a(0.0,0.0);
    if(dis(b,c)<eps) return 0.0;
    double h=fabs(cross(a,b,c))/dis(b,c);
    if(dis(a,b)>r-eps&&dis(a,c)>r-eps)//两个端点都在圆的外面则分为两种情况
    {
        double angle=acos(dot(a,b,c)/dis(a,b)/dis(a,c));//这个就是上图的seta 
        if(h>r-eps) return 0.5*r*r*angle;//这个就是1(1)的情况 
		else  if(dot(b,a,c)>0&&dot(c,a,b)>0)//如果都是锐角 这就是算的面积 
        {
            double angle1=2*acos(h/r);
            return 0.5*r*r*fabs(angle-angle1)+0.5*r*r*sin(angle1);
        }else return 0.5*r*r*angle;
    }else 
        if(dis(a,b)<r+eps&&dis(a,c)<r+eps) return 0.5*fabs(cross(a,b,c));//两个端点都在圆内的情况
        else//一个端点在圆上一个端点在圆内的情况
        {
            if(dis(a,b)>dis(a,c)) swap(b,c);//默认b在圆内
            if(fabs(dis(a,b))<eps) return 0.0;//ab距离为0直接返回0
            if(dot(b,a,c)<eps)
            {
                double angle1=acos(h/dis(a,b));
                double angle2=acos(h/r)-angle1;
                double angle3=acos(h/dis(a,c))-acos(h/r);
                return 0.5*dis(a,b)*r*sin(angle2)+0.5*r*r*angle3;
            }else
            {
                double angle1=acos(h/dis(a,b));
                double angle2=acos(h/r);
                double angle3=acos(h/dis(a,c))-angle2;
                return 0.5*r*dis(a,b)*sin(angle1+angle2)+0.5*r*r*angle3;
            }
        }
}
int main()
{
    double x,y,R;//圆心+半径 
    double Ax,Ay,Bx,By;
        scanf("%lf%lf%lf%lf%lf%lf%lf",&x,&y,&R,&Ax,&Ay,&Bx,&By);
        p[1].x=Ax;p[1].y=Ay;//初始化凸多边形顶点时按照顺时针方形或者逆时针,我这里是按照顺时针 
        p[2].x=Ax;p[2].y=By;
        p[3].x=Bx;p[3].y=By;
        p[4].x=Bx;p[4].y=Ay;
        p[5]=p[1];//需要多存一个起始点 
        Point O(x,y);// 初始化圆心坐标 
        for(int i=1;i<=5;i++) p[i]=p[i]-O;//向量 
        O=Point(0,0);//把圆心转化为了原点,这点很重要,这点如何理解?就是向量的几何意义和代数的转化 
        double sum=0;
        for(int i=1;i<=4;i++)
        {
            int j=i+1;
            double s=area(p[i],p[j],R);
            if(cross(O,p[i],p[j])>0) sum+=s;//这里就是判断方向面积的正负 
			else sum-=s;
        }
        printf("%.4lf\n",fabs(sum));//最后输出绝对值 
    return 0;
}

Beer Marathon

题目链接

In the booths version of the popular annual Beer Marathon, many beer booths (also called beerstalls or beer stands) are installed along the track. A prescribed number of visits to difffferentbeer booths is a part of the race for all contestants. The distances between any two consecutivebeer booths should be exactly the same and equal to the particular value specifified in the racerules. The company responsible for beer booths installation did the sloppy work (despite being excessively paid), left the beer booths on more or less random positions along the track and departedfrom the town. Fortunately, thanks to advanced AI technology, the company was able to reportthe exact positions of the beer booths along the track, measured in meters, with respect tothe particular anchor point on the track. The marathon committee is going to send out thevolunteers to move the beer booths to new positions, consistent with the race rules. They want to minimize the total number of meters by which all beer booths will be moved.The start line and the fifinishing line of the race will be chosen later, according to the resultingpositions of the beer booths.

Input Specifification

The fifirst line of input contains two integers N and K (1 ≤ N, K ≤ 106), where N is the numberof beer booths and K is the prescribed distance between the consecutive beer booths. Thesecond line of input contains N pairwise difffferent integers x1, . . . , xN ( -106 ≤ xi ≤ 106), theoriginal positions, in meters, of the beer booths relative to the anchor point. The positive valuesrefer to the positions past the anchor point and the negative values refer to the positions beforethe anchor point.

Output Specifification

Output a single integer — the minimal total number of meters by which the beer booths shouldbe moved to satisfy the race rules.

1.题目大意:在坐标x轴上有n个物体,现在给出一个距离k,要移动物体使得所有物体的间距为k,求最小的移动总距离

2.比赛时我想到了二分查找,但是很遗憾没想到三分查找。但是之前只做过一次三分查找的题目,估计现在也已经忘记如何运用了。实际上我们假设最终状态中点为起点,分别向两边延伸,假设k为4,那么不就是得到了一个如下的凹函数模型吗

在这里插入图片描述
3.我们得到了这个模型,但是中点并不好查找,但是我们可以只查找这个线段的左右起点即可。题目的最优解会对应一个起点,该起点最终存在,取区间范围 [-1e12,1e12] 为较大的边界,定义L、R在该范围内用类似三分查找,查找该起点,每次查找计算两个起点对应的移动所需距离,左起点midl为(L+R)/2,右起点midr =(midl+R)/2。如果左起点对应所需移动的距离小于右起点,则右起点R=midr, 左起点L不变。如果右小于左则相反,取每次计算结果的最小值。另外查找的结束不能设置为while(L<R),会超时,这类问题在三分查找例题中也有,那么就设置循环次数为100次,1e8 时间复杂度

4.题目的数据也要注意,我们第一次设置的INF的值大小应为1e18,为什么呢?假设1e6个点均在同一点附近,而且k为1e6那么,最多需要n2*k≈1e18的移动距离,这也卡了我挺长时间

#include <iostream>
#include <cstring>
#include <math.h>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
#define INF 1e18
ll L,R;
int a[1000010];
int n,k;

ll solve(ll s){
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans+=abs(a[i]-s);
        s+=k;
    }
    return ans;
}

ll tri_search(){
    ll ans0=INF,ans1,ans2;
    ll midl,midr;
    for(int i=1;i<=100;i++){
        midl=(L+R)/2;
        midr=(midl+R)/2;
        ans1=solve(midl),ans2=solve(midr);
        ans0=min(ans0,min(ans1,ans2));
        if(ans1>=ans2) L=midl;
        else R=midr;
    }
    return ans0;
}

int main()
{
    while(scanf("%d%d",&n,&k)!=EOF){
        L=-1e12+10,R=1e12+10;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);
        printf("%lld\n",tri_search());
    }
    return 0;
}

发布了128 篇原创文章 · 获赞 7 · 访问量 5277

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/104494158