衡阳八中noip2014模拟赛day1

衡阳八中noip2014模拟赛day1

T1国色天香

题目简要:给出火柴棒的根数,问拼出数字的最大最小值
解答:
火柴棒拼数字1 2 3 4 5 6 7 8 9 0
需要火柴棒 2 5 5 4 5 6 3 7 6 6
对于最大值,我们首先要保证最多的位数,即尽可能多的摆1(因为它需要的火柴棒数2最小),对于n%2==1的情况,我们只需将最高位改为7(需要3根)。
对于最小值,我们同样首先需要保证最小的位数,即尽可能的摆8(需要7根)。对于余下不同火柴棒的情况:
n%7==1
将最高位8换为10
n%7==2
在最高位前添加1
n%7==3
(1)n==3 最高位前添加7
(2)n==10 最高位8变为22
(3)n==17 最高位88变为200
n%7==4
(1)n==4 最高位前添加4
(2)n==11 最高位8变为20
n%7==5
最高位前添加2
n%7==6
最高位前添加6
附代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
//2,5,5,4,5,6,3,7,6,6;
void findmax(int x)
{
    int m=x;
    if(m&1)putchar('7'),m-=3;
    for(;m;m-=2)putchar('1');
    putchar(' ');
    return;
}
void findmin(int x)
{
    int m=x;
    switch(m%7)
    {
        case 1:
            putchar('1'),putchar('0');
            m-=8;
            break;
        case 2:
            putchar('1');
            m-=2;
            break;
        case 3:
            if(m==3)
            {
                putchar('7');
                m-=3;
            }
            else if(m==10)
            {
                putchar('2'),putchar('2');
                m-=10;
            }
            else
            {
               putchar('2'),putchar('0'),putchar('0');
               m-=17;   
            }
            break;
        case 4:
            if(m==4)
            {
                putchar('4');
                m-=4;
            }
            else
            {
                putchar('2'),putchar('0');
                m-=11;
            }
            break;
        case 5:
            putchar('2');
            m-=5;
            break;
        case 6:
            putchar('6');
            m-=6;
            break;
    }
    for(;m;m-=7)putchar('8');
    putchar(10);
    return;
}
int main()
{
    int T,x;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&x);
        findmax(x);
        findmin(x);
    }
    return 0;
} 

T2无语凝噎

未完待续。。。
题解也看不懂怎么破。。好吧,我们来看第三题

T3福慧双修

其实不是完全搞懂了。有时间再做一遍。
吐槽一下,名字起的这么雷人真的好吗,剧情这么假真的好吗。。。
题目简要:给出一个无向图,每条边正向,反向需要的时间不同(这不就是有向图吗。。),且一条路只能通过一回,问从1回到1需要的最短时间。
题目解析:看完题目我的第一想法是建立一个新点当作终点,它的入/出度与1完全相同,但YY了一下发现很难保证每条边只走一遍。于是就跑去看题解啦。
题解是这样的,思路其实也是建立新点,但构图非常不同。
首先要跑一遍spfa,求出每一个点到1的最短距离dis[i],并记录prev[i]表示这条路径上与1相连的点的标号。然后——>注意前方高能。
枚举图中每一条边

Part1:该边为x连向1,边权为value。

(1)当prev[x]!=x说明从1到x的最短路并没有经过这条边,故在新图中建立一条从起点到终点的边,边权为value+dis[u]
(2)当prev[x]==x即不能再走该边,在新图中建立从x到终点的边,边权为value.

Part2:该边为从1连向x,边权为value

(1)当prev[x]=x,说明原图中即存在这样的最短边
(2)当prev[x]!=x,说明原点到达v的最短路径不是改边,故在新图中建立从1到x的边,边权为value.

Part3:该边的起点和终点均不为1.

(1)当prev[u]!=prev[v],说明原点到达两端点的最短路径是不同的,即存在一条从1到v,边权为dis[u]+value.
(2)当prev[u]==prev[v],在新图中保留原边。

最后在新图中求一次从1到n+1的最短路。
贴代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define maxn 50048
#define maxm 100003
using namespace std;
struct node{
    int to,from,val,next;
};
node e[maxm*2],en[maxn*2];
int head[maxn];
int dis[maxn];
int prev[maxn];
bool vis[maxn];
int tot,totn;
int n,m;
void add(int x,int y,int u)
{
    e[++tot].to=y;
    e[tot].from=x;
    e[tot].val=u;
    e[tot].next=head[x];
    head[x]=tot;
}
void newadd(int x,int y,int u)
{
    en[++totn].to=y;
    en[totn].from=x;
    en[totn].val=u;
    en[totn].next=head[x];
    head[x]=totn;
}
void spfa()
{
    memset(dis,0x7f7f7f7f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    queue<int> Q;
    Q.push(1);vis[1]=1;dis[1]=0;
    while(Q.size())
    {
        int p=Q.front();Q.pop();
        vis[p]=0;
        for(int k=head[p];k;k=e[k].next)
        {
            int v=e[k].to;
            if(dis[v]>dis[p]+e[k].val)
            {
                dis[v]=dis[p]+e[k].val;
               if(p==1) prev[v]=v;
                 else prev[v]=prev[p];
               if(!vis[v])vis[v]=true,Q.push(v);
            }    
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);

    tot=0;
    int u,v,w,y;
    memset(head,0,sizeof(head));
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d%d",&u,&v,&w,&y);
        add(u,v,w);
        add(v,u,y);
    }

    spfa();
    //½¨Á¢ÐÂͼ
    totn=0;
    for(int i=1;i<=n;i++)
     for(int k=head[i];k;k=e[k].next)
        {
            if(e[k].to==1)
            {
               if(prev[i]==i)newadd(i,n+1,e[k].val);
                else newadd(1,n+1,e[k].val+dis[i]);
            }
            else if(i==1)
            {
               int v=e[k].to;
               if(prev[v]==v)continue;
               newadd(1,v,e[k].val);
            }
            else
            {
                int v=e[k].to;
                if(prev[i]==prev[v])newadd(i,v,e[k].val);
                else newadd(1,v,dis[i]+e[k].val);
            }
       }
    //ÔÚԭͼÉÏÖØй¹½¨ÐÂͼ£¬ÖØÐÂÀûÓÃspfa()º¯Êý 
    tot=0;
    memset(head,0,sizeof(head));
    for(int i=1;i<=totn;i++)
    {
        int pu=en[i].to;
        int pv=en[i].from;
        int pw=en[i].val;
        add(pv,pu,pw);
    }
    spfa();
    int ans=dis[n+1];
    if(ans==0x7f7f7f7f)ans=-1;
    printf("%d\n",ans);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值