HCPC 2011 Spring Online Contest解题报告

一篇关于HCPC2011春季在线竞赛的详细解题报告,涵盖从简单到复杂的多种题型,包括RPNF、默认密码、审查制度、最终战斗幻想、服装派对、回家等不同类型的题目。报告中提供了各种题目的解决思路和代码实现,从字母输出、运算符优先级处理、字符串匹配到数学方程组的求解,再到搜索算法和图论问题的解决,以及计算几何问题的探讨。同时,报告也涉及到了一些基础概念的解释和代码优化的思考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HCPC 2011 Spring Online Contest解题报告

A题 RPNF

悲了个催,这种题一直是令我纠结的一种题,表达式求值。。。应该找个时间把这类的正解学下,不能总是现场YY。。。一个堆栈操作的过程,

1.遇到字母直接输出

2.遇到运算符或者左括号op,从栈顶开始,依次与op比较,若优先级大于op,则出栈输出,直到栈为空或者栈顶操作符优先级小于op或者栈顶为'('然后op进栈

3.遇到')',一直出栈,直到栈顶为'('这样就把问题完美解决了代码:

#include <stdio .h>
#include <ctype .h>
#define N 300
char st[N],stack[N];
int priority(char op)
{
    switch(op)
    {
        case '+':return 0;
        case '-':return 1;
        case '*':return 2;
        case '/':return 3;
        case '^':return 4;
        default:return 5;
    }
}
bool cmp(char op1,char op2)
{
    return priority(op1)>=priority(op2);
}
int main()
{
    int t,i,top;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",st);
        top=0;
        for(i=0;st[i];i++)
        {
            if(isalpha(st[i]))putchar(st[i]);
            else
            {
                   if(st[i]==')')
                   {
                       while(top&&stack[top]!='(')putchar(stack[top--]);
                       top--;
                   }
                   else
                   {
                       while(top&&stack[top]!='('&&cmp(stack[top],st[i]))putchar(stack[top--]);
                       stack[++top]=st[i];
                   }
            }
        }
        while(top)putchar(stack[top--]);
        puts("");
    }
    return 0;
}


B题 Default Password

o(∩∩)o...哈哈,大水题,让所有人都能happy的过掉,但要比手速。。水题刷刷更健康~~~~

#include <iostream>
 
using namespace std;
 
int main()
{
    string st;
    while(cin>>st)
    {
        if(st=="wujiawei")cout< <"hit";else cout <<"lose";
        cout<<endl;
    }
    return 0;
}


C题Censorship

额,对题意有些疑问,样例没看懂,感觉第三个样例答案应该是3有空再研究。。。

C题The Final Battle of Daydream

题意:给出1..n中的n-2个数,输出少了的两个数
比赛时内存给了1M,但是数据范围是300,000
挂在oj的题上显示给的内存是64M,应该是出问题了吧。。。


起初我就是开了个布尔数组,但是一直超内存,也就超一点点,眼看着别人一个个AC,心里那个滋味啊。。。。


后来看到最下面一行PS. because of the limit memory, iostream is not recommanded.
然后顿悟,去掉了#include<iostream>,然后就AC了


这么做绝对是水过,算一下内存:sizeof(bool)得到1,也就是1个字节,300,000B, 不知道hoj是否算的是字节,问下1+学长


正确的做法是根据给出的数列出两个方程组成方程组,解出答案


a+b=sum(n)-sum(left)
a^2+b^2=sum(n^2)-sum(left^2)


然后解出a和b
正解:

改编自OnePlus学长空间里的解题报告

#include <cstdio>
#include <cstring>
#include <cmath>
#define sqr(x) ((x)*(x))
#define PRINT(x) cout < <(#x)<<" "<<x<<endl;
using namespace std;
int main() {
    double n;
    while(scanf("%lf",&n)==1){
        double N = 0.0, M = 0.0;
        for(double i = 1; i <= n; i ++ ) {
            N = N + i;
            M = M + sqr(i);
        }

        N = ( 1 + n ) * n / 2;
        M = ( n + 1 ) * ( n*2+1)*n/6;
        for(int i = 2; i < n; i ++) {
            double x; scanf( "%lf", &x );
            N = N - x; M = M - sqr(x);
        }
        double delta = sqrt(2.0 * M - sqr(N));
        //printf( "TEST %.10lf %.10lf %.10lf\n", N, M, delta);
        double x = 0.5 * (N - delta), y = 0.5 * (N + delta);
        printf( "%.0lf %.0lf\n", x, y );
    }
    return 0;
}

水解:

#include <stdio .h>
#include <string .h>
#define N 300001
bool f[N];
int main()
{
    int n,i,a,tot;
    while(scanf("%d",&n)==1)
    {
        memset(f,0,sizeof(f));
        tot=0;
        for(i=0;i<n -2;i++)
        {
            scanf("%d",&a);
            f[a]=1;
        }
        for(i=1;i<=n;i++)
            if(!f[i])
            {
                if(tot)putchar(' ');
                tot++;
                printf("%d",i);
            }
        puts("");
    }
    return 0;
}


E题Costume Party

数学+搜索题

dfs找染色方案,每找出一种染色方案,使用的颜色总数为m1,则ans += A(m,m1)

#include <iostream>
#define N 13
using namespace std;
int tot_edge,n,m,ans;
int MOD=9999997;
struct data
{
    int v;
    data*next;
}*adj[N],edge[N*N*2];
int visit[N],visitcol[N];
void push_edge(int u,int v)
{
    edge[tot_edge].v=v;
    edge[tot_edge].next=adj[u];
    adj[u]=&edge[tot_edge++];
}
long long a(int n,int m)
{
    long long ans=1;
    while(m--)
    {
        ans=ans*n%MOD;
        n--;
    }
    return ans;
}
void dfs(int k)
{
    int i;
    if(k==n)
    {
        int totcol=0;
        for(i=1;i< =n;i++)
            if(visitcol[i])totcol++;
        if(totcol<=m)ans=(ans+a(m,totcol))%MOD;
        return;
    }
    data *temp=adj[k];
    bool color[N]={false};
    while(temp)
    {
        if(visit[temp->v])
            color[visit[temp->v]]=true;
        temp=temp->next;
    }
    for(i=1;i< =n;i++)
        if(!color[i]&&visitcol[i])
        {
            visit[k]=i;
            dfs(k+1);
        }
    for(i=1;i<=n;i++)
        if(!visitcol[i])break;
    if(i<=n)
    {
        visit[k]=i;
        visitcol[i]=1;
        dfs(k+1);
        visitcol[i]=0;
    }
    visit[k]=0;
}
int main()
{
    int k,a,b,i,cas=1;
    while(scanf("%d %d %d",&m,&n,&k)==3)
    {
        tot_edge=0;
        memset(adj,0,sizeof(adj));
        for(i=0;i<k;i++)
        {
            scanf("%d %d",&a,&b);
            a--;
            b--;
            push_edge(a,b);
            push_edge(b,a);
        }
 
        memset(visit,0,sizeof(visit));
        memset(visitcol,0,sizeof(visitcol));
        ans=0;
        dfs(0);
        printf("Case #%d\n%d\n",cas++,ans);
    }
    return 0;
}


F题Go Home

给了张图,每条边有个距离,还有个费用,求不超过此费用的最短路


我用spfa做的,保留了个二维的读列,但是比较慢,0.22s


看了OnePlus学长博客的<a href="http://www.oneplus.info/archives/230">解题报告</a>,给的做法是堆优化的dijkstra,我用xiaohao2跑了下,0.04s,挺快,直接用的algorithm里的堆(学习下)


OnePlus学长还给了个搜索做的,写的是宽搜,我提交后,时间好慢,0.28s,也许是因为用模板了。。。


看到wdk的只用了0.02s,orz。。。然后问他怎么做到的,他说直接搜索(深搜),看来我水了。。这道题水了。。。搜索竟然比正解快,搜索才是正解。。。。


然后我也写了个深搜,0.01s过掉,回头想了下先前写的spfa,也不过就是宽搜,但是宽搜怎么会比深搜慢那么多倍(都木有用到模板),改了很多次,bfs还是那么慢,纠结。。。。


有谁知道是怎么回事呀。。。


spfa(bfs)写法(变量名有点乱,囧。。。)
#include<stdio .h>
#include<string .h>
#define M 2010
#define N 510
#define NN 250010
struct data
{
    int v,co,tm;
    data*next;
}*adj[N],edge[M];
int q[NN],f[N][N],cost[NN],visit[N][N];
int C,tot_edge,n;
void push_edge(int u,int v,int c,int t)
{
    edge[tot_edge].v=v;
    edge[tot_edge].co=c;
    edge[tot_edge].tm=t;
    edge[tot_edge].next=adj[u];
    adj[u]=&edge[tot_edge++];
}
void spfa()
{
    q[0]=1;
    cost[0]=C;
    f[1][C]=0;
    int head=-1,tail=1,u,t,c;
    data*tmp;
    while((head+1)%NN!=tail)
    {
        head++;
        head%=NN;
        u=q[head];
        c=cost[head];
        t=f[u][c][/c];
        tmp=adj[u];
        visit[u][c][/c]=0;
        while(tmp)
        {
            if(c>=tmp->co&&f[tmp->v][c language="-tmp->co"][/c]>t+tmp->tm)
            {
                f[tmp->v][c language="-tmp->co"][/c]=t+tmp->tm;
                if(tmp->v!=n&&tmp->v!=1&&!visit[tmp->v][c language="-tmp->co"][/c])
                {
                    q[tail]=tmp->v;
                    cost[tail]=c-tmp->co;
                    visit[tmp->v][c language="-tmp->co"][/c]=1;
                    tail++;
                    tail%=NN;
                }
            }
            tmp=tmp->next;
        }
    }
}
int main()
{
    int T,t,m,i,u,v,c,INF,ans;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d",&n,&m,&C);
        tot_edge=0;
        memset(adj,0,sizeof(adj));
        for(i=0;i<m ;i++)
        {
            scanf("%d %d %d %d",&u,&v,&c,&t);
            push_edge(u,v,c,t);
            push_edge(v,u,c,t);
        }
        memset(visit,0,sizeof(visit));
        memset(f,127,sizeof(f));
        ans=INF=f[0][0];
        spfa();
        for(i=0;i<=C;i++)
            if(f[n][i]<ans)ans=f[n][i];
        if(ans==INF)puts("-1");
        else printf("%d\n",ans);
    }
    return 0;
}

dfs 写法:
#include<stdio .h>
#include<string .h>
#define N 510
#define M 2010
#define INF 1000000000
int n,tot_edge,ans;
bool visit[N];
struct data
{
    int v,c,t;
    data * next;
    void update(int v,int c,int t,data *k)
    {
        this->v=v;
        this->c=c;
        this->t=t;
        this->next=k;
    }
}edge[M],*adj[N];
void push_edge(int u,int v,int c,int t)
{
    edge[tot_edge].update(v,c,t,adj[u]);
    adj[u]=&edge[tot_edge++];
}
void dfs(int k,int left,int tim)
{
    if(tim>=ans)return;
    if(k==n)ans=tim;
    else
    {
        visit[k]=true;
        data*temp=adj[k];
        while(temp)
        {
            if(!visit[temp->v]&&left>=temp->c)
                dfs(temp->v,left-temp->c,tim+temp->t);
            temp=temp->next;
        }
        visit[k]=false;
    }
}
int main()
{
    int t,i,a,b,c,m,C,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d",&n,&m,&C);
        tot_edge=0;
        memset(adj,0,sizeof(adj));
        for(i=0;i<m ;i++)
        {
            scanf("%d %d %d %d",&a,&b,&c,&t);
            push_edge(a,b,c,t);
            push_edge(b,a,c,t);
        }
        ans=INF;
        memset(visit,false,sizeof(visit));
        dfs(1,C,0);
        if(ans==INF)puts("-1");
        else printf("%d\n",ans);
    }
}

dijkstra+堆优化:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 505;
const int INF = 0x3fffffff;
int first[N];
int cnt = 1;
struct edge
{
    int u, v, c, t, next;
} g[N * 4];

void add(int u, int v, int c, int t)
{
    g[cnt].u = u;
    g[cnt].v = v;
    g[cnt].c = c;
    g[cnt].t = t;
    g[cnt].next = first[u];
    first[u] = cnt++;
}

struct node
{
    int w, u, t;
    bool operator < ( const node &a ) const
    {
        return t > a.t;
    }
};

int n, m, C;

int dis[N][N];
bool used[N][N];
node queue[N * N];

bool relax(int u, int w, int v, int c, int t)
{
    if (dis[u][w] + t < dis[v][w + c])
    {
        dis[v][w + c] = dis[u][w] + t;
        return true;
    }
    return false;
}

void dij(int u)
{
    for (int i = 0; i <= n; ++i) for (int j = 0; j <= C; ++j) dis[i][j] = INF;
    memset(used, false, sizeof(used));

    int tail = 0;
    int v, w, c, t;

    dis[u][0] = 0;
    queue[tail].u = u;
    queue[tail].w = 0;
    queue[tail].t = 0;
    tail++;
    make_heap(queue, queue + tail);

    while (tail > 0)
    {
        pop_heap(queue, queue + tail);
        tail--;
        u = queue[tail].u;
        if ( u == n ) break;
        w = queue[tail].w;
        if ( !used[u][w] )
        {
            used[u][w] = true;
            for (int tmp = first[u]; tmp ; tmp = g[tmp].next)
            {
                v = g[tmp].v;
                c = g[tmp].c;
                t = g[tmp].t;
                if ( w + c < = C && !used[v][w + c] && relax(u, w, v, c, t) )
                {
                    queue[tail].u = v;
                    queue[tail].w = w + c;
                    queue[tail].t = dis[v][w + c];
                    tail++;
                    push_heap(queue, queue + tail);
                }
            }
        }
    }
    return;
}

int main()
{
    int cases, u, v, c, t;
    scanf("%d", &cases);
    while (cases--)
    {
        memset(first, 0, sizeof(first));
        cnt = 1;
        scanf("%d %d %d", &n, &m, &C);  // n:1~n
        for (int i = 0; i < m; ++i)
        {
            scanf("%d %d %d %d", &u, &v, &c, &t);
            add(u, v, c, t);
            add(v, u, c, t);
        }

        dij(1);

        int ans = INF;
        for (int i = C; i >= 0; --i)
        {
            if (dis[n][i] != INF)
            {
                ans = min(ans, dis[n][i]);
            }
        }
        printf("%d\n", ans == INF ? -1 : ans);
    }
    return 0;
}


G题Alex's Problem

万恶的计算几何啊。。。鸭梨很大。。。
求截面面积。。。。坑爹啊。。。。更坑爹的是学长竟然做下来啦。。。


Alex 的problem很严重啊


没那份耐心去想,此题报告待写。。。

H题Zhou Yi II

水题,蛮好。。。
二进制转十进制。。。。
#include <iostream>
 
using namespace std;
 
int main()
{
    char st[100];
    int n,i,ans;
    while(scanf("%d",&n)==1)
    {
        getchar();
        ans=0;
        for(i=0;i<n ;i++)
        {
            gets(st);
            ans<<=1;
            if(strcmp(st,"---"))
                ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

Okay,网络赛的报告就写到这,其中两道题待做,会尽快做掉。。。。
就这报告还写了这么长时间。。。。咳咳。。。不过很爽,很久都没安静做题了,这回泡在图书馆一下午+晚上,安安静静的做完这些事,挺好。。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值