2016年中国大学生程序设计竞赛(杭州)-重现赛【01,02,03,06】

说些感触。

= =、哎,说起来重现还真是好气啊。

出去的大二过去两题打铁,今天我们队边玩边打过了4题,有点不甘心啊。= =、对教练略无奈。

-------------------------

比赛经验:

今天一开始,我洗完澡回来,比赛已经开始15分钟了,yhp和zmy都还在看题意,然后zmy在我来的时候已经在敲02了(其实是03,他说是02),然后我就和yhp讨论01,01yhp说完题意,一脸蒙比,因为知道01是水题吧,所以就开始瞎yy........(中间yy略去),后来我们过了01(wa了很多,我记得第一发T了,数组开小,这种低智商的错误也犯了)。然后窝去找zmy看03,C题一读完,卧槽,那么简单。。。zmy陷入了一个很烂的思路(其实这个每个人都有),但是严重的是,如果是现场赛,那不就完蛋了。我一直在想一个最不好的情况,那就是两个人在搞一道题目,而另一个人陷入了一道不是很难的水题不能自拔。这是最烂的,首先zmy因为这题(后来yhp和窝开始重新搞,wa了一发,也过了)心态不好了,心态很重要很重要!!比赛的时候心态很重要,不要脸地说,今天4题有3题基本上是我主导思路,然后过的,自信很重要,心态很重要!后来搞那个06,yhp瞎yy了一个方案,后来zmy搞出来在<8的情况是错的,后来一致决定<8暴力,然后wa了,因为输出用了%d....2333,最后的02,一直想一直想,最后队友给我讲了有可能环带有支路,那么就是强连通缩点,搞完1A。

应该在现场赛就能拿铜了。。。。。心好痛。。。。。。

不过真的,今天边玩边打场,比赛经验就是:心态很重要!

还有以后的策略,除非是很水很水的题,操盘>=两个人!而另一个人要死命去读别的题,做好一旦那个题A出或者没A出的衔接工作,每个人都要有担当;

写几发题解;

---------------

11还在酝酿。。。。。。


01:

题意:

给你n个值,让你搞成m个相等的值,一种操作是把a[i]只能分成相邻两部分,另一种操作是把a[i]和a[i+1]合并,求最小操作数;

思路:

首先肯定是求个所有值的sum,并且sum%m==0,搞一个平均值aver

就是如果对于当前a[i]<aver,那么就往前面拿,如果是a[i]+a[i+1]<=aver那么就是直接合并,最后出来的时候判断一下a[i]就好了;

如果对于a[i]>aver,那么就要分,那么肯定是分aver出去,分到小于等于aver为止,然后还要处理剩下的;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
using namespace std;
#define INF 0x3f3f3f
#define pi acos(-1.0)
#define mod 9973
typedef long long LL;

const int MAX=100010;
LL n,m;
LL a[MAX];

int main()
{
    LL t,i,j;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        LL sum=0;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
        {
            scanf("%lld",&a[i]);
            sum+=a[i];
        }
        printf("Case #%d: ",cas++);
        if(sum%m!=0)
        {
            printf("-1
");
            continue;
        }
        LL aver=sum/m;
        LL cont=0;
        for(i=0;i<n;i++)
        {
            if(a[i]<aver)
            {
                LL tmp=a[i];
                while(i+1<n&&(tmp+a[i+1])<=aver)
                {
                    tmp+=a[i+1];
                    i++;
                    cont++;
                }
                if(tmp<aver)
                {
                    cont+=2;
                    a[i+1]-=aver-tmp;
                }
            }
            else if(a[i]>aver)
            {
                while(a[i]>aver)
                {
                    cont++;
                    a[i]-=aver;
                }
                if(i+1<n&&a[i]<aver)
                {
                    LL tmp=a[i];
                    while(i+1<n&&(tmp+a[i+1])<=aver)
                    {
                        tmp+=a[i+1];
                        i++;
                        cont++;
                    }
                    if(tmp<aver)
                    {
                        cont+=2;
                        a[i+1]-=aver-tmp;
                    }
                }
            }
        }
        printf("%lld
",cont);
    }
    return 0;
}

02:

题意:

给你n个炸弹(一开始理解成了灯。。)的坐标,范围,花费,a炸了,b在a炸弹的边界或者里面,b也炸了,以此类推;

思路:

强连通,缩点,然后取一个点集里面最小的花费作为这个点的花费,然后把入度为零的点的花费加起来就好了;

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
const double INF = 0x3f3f3f3f;
typedef long long LL;
const int N = 1e3+10;


struct asd{
    LL x;
    LL y;
    LL w;
    LL cash;
};
asd q[N];
int pre[N];
int ma[N][N];
int dfn[N];
int low[N];
int stap[N];
int vis[N];
int in[N];
int tp,p,cnt;
LL ww[N];
int kr[N];
int n;

bool Judge(int i,int j)
{
    if(i==j)
        return false;
    if(((q[i].x-q[j].x)*(q[i].x-q[j].x)+(q[i].y-q[j].y)*(q[i].y-q[j].y))<=(q[i].w*q[i].w))
        return true;
    return false;
}

void tarjan(int u)
{
    dfn[u]=low[u]=++tp;
    stap[++p]=u;
    vis[u]=1;
    for(int i=1;i<=n;i++)
    {
        if(!ma[u][i])
            continue;
        if(!dfn[i])
        {
            tarjan(i);
            low[u]=min(low[u],low[i]);
        }
        else if(vis[i])
        {
            low[u]=min(low[u],dfn[i]);
        }
    }
    if(dfn[u]==low[u])
    {
        cnt++;
        int temp;
        while(1)
        {
            temp=stap[p];
            vis[temp]=0;
            in[temp]=cnt;
            ww[cnt]=min(ww[cnt],q[temp].cash);
            p--;
            if(temp==u)
            {
                break;
            }
        }
    }
}
void fun()
{

    memset(kr,0,sizeof(kr));

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(ma[i][j]&&in[i]!=in[j])
            {
                kr[in[j]]++;
            }
        }
    }
    LL ans=0;
    for(int i=1;i<=cnt;i++)
    {
        if(!kr[i])
        {
            ans+=ww[i];
        }
    }
    printf("%lld
",ans);
}

void init()
{
    memset(ma,0,sizeof(ma));
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(ww,INF,sizeof(ww));
}

int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld%lld%lld%lld",&q[i].x,&q[i].y,&q[i].w,&q[i].cash);
        init();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(Judge(i,j))
                    ma[i][j]=1;
            }
        }

        tp=p=cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
                tarjan(i);
            }
        }
        printf("Case #%d: ",cas++);
        fun();
    }
    return 0;
}

03:

题意:

有一辆车,通过n个位置,通过每个位置的时间点都是整数,在整个过程中车的速度是非递减的。

思路:

那么就是说最后那个区间速度最大,时间最短,而且是整数秒,那么就是1秒,然后对于每个区间就是求一个向上取整时间(以前和队友考虑过)(n+m-eps)/m;

(被除数+除数-精度)/除数;)也没怎么注意就用了long long

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
using namespace std;
#define INF 0x3f3f3f
#define pi acos(-1.0)
#define mod 9973
typedef long long LL;

const double eps=1e-6;
const int MAX=100010;
int n,m;
double a[MAX],b[MAX];

int main()
{
    int i,j;
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            if(i==1)
            {
                scanf("%lf",&a[i]);
                b[i]=a[i];
            }
            else
            {
                scanf("%lf",&a[i]);
                b[i]=a[i]-a[i-1];
            }
        }
        double tmp=b[n];
        LL ans=0;
        ans+=1;
        for(i=n-1;i>=1;i--)
        {
            if(b[i]<=tmp)
            {
                ans+=1;
                tmp=b[i];
            }
            else
            {
                LL tt=(b[i]+tmp-eps)/tmp;
                ans+=tt;
                tmp=b[i]/(double)tt;
//                printf("%lld
",tt);
            }
//            printf("%lf
",tmp);
        }
        printf("Case #%d: ",cas++);
        printf("%lld
",ans);
    }
    return 0;
}

06:

题意:

给你一串数,让你依次分割成5串,做+-*/运算,*/优先,求最大值;

思路:

队友一开始想就是前面位数越多越好,就是两种可能首位+第二位到倒数第四位或者首位到倒数第五位构成的数+倒数第四位;

后来长度为6或7的时候有出路,一致同意<=8的情况下暴力,然后用暴力测所有情况,感觉没问题就过了;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
using namespace std;
#define INF 0x3f3f3f
#define pi acos(-1.0)
#define mod 9973
typedef long long LL;

const double eps=1e-6;
const int MAX=100010;
int n,m;

char s[21];

LL get_num(int ss,int t)
{
    LL ans=0;
    for(int i=ss; i<t; i++)
    {
        ans=ans*10+s[i]-'0';
    }
    return ans;
}

int main()
{
    int i,j,k,h;
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        scanf("%s",s);
        printf("Case #%d: ",cas++);
        n=strlen(s);
        LL ans1=0;
        ans1=(s[n-3]-'0')*(s[n-2]-'0')/(s[n-1]-'0');
        ans1=-ans1;
        LL sum1=0,sum2=0;
        if(n<=8)
        {
            LL ans=-INF;
            for(i=1; i<(n-3); i++)
            {
                for(j=i+1; j<(n-2); j++)
                {
                    for(k=j+1; k<(n-1); k++)
                    {
                        for(h=k+1; h<n; h++)
                        {
//                            printf("%d %d %d %d 
",i,j,k,h);
                            ans=max(ans,get_num(0,i)+get_num(i,j)-get_num(j,k)*get_num(k,h)/get_num(h,n));
//                            printf("%lld
",ans);
                        }
                    }
                }
            }
            printf("%lld
",ans);
            continue;
        }
        for(i=0; i<n-4; i++)
        {
            sum1=sum1*10+s[i]-'0';
        }
        for(i=1; i<=n-4; i++)
        {
            sum2=sum2*10+s[i]-'0';
        }
        sum1+=s[n-4]-'0';
        sum2+=s[0]-'0';
        LL sum=max(sum1,sum2);
        printf("%lld
",sum+ans1);


    }
    return 0;
}



原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6216769.html