洛谷P5207 [WC2019]远古计算机

题目背景

企鹅大陆是一片神奇的土地,在厚厚的冰层下埋藏着一个巨大的宝藏。探险家企鹅豆豆挖穿冰层到达了宝库,但他发现了一个令人发愁的问题。一共有五座宝库,每个宝库是由某些远古计算机控制的。由于年代久远,这些计算机里的程序已经消失不见了,只有给这些计算机重新填写代码并且顺利运行,输出了正确结果才能触发开门的机关。

题目描述

每一个宝库大门由一个计算机集群控制,计算机之间用数据线相连以便传输数据。但是有很多数据线已经损坏了,所以只留下了一部分连线。一开始数据线上没有数据,当一台计算机向数据线上写入时,数据线上就有了一个整数。每条数据线上最多可以同时传输一个整数,当整数被读取后便会消失,数据线就又回到没有数据的状态。

每台远古计算机有两个储存单元,分别名为 aa 和 bb,每个储存单元能够储存一个 -2147483648−2147483648 到 21474836472147483647 之间的整数。

每个时刻,每台远古计算机可以执行一条指令,一共有以下几种指令:

  • mov reg val:将储存单元 reg 的值赋值为 val 的值;
  • add reg val:给储存单元 reg 加上 val 的值;
  • dec reg val:给储存单元 reg 减去 val 的值;
  • mul reg val:给储存单元 reg 乘以 val 的值;
  • div reg val:给储存单元 reg 除以 val 的值,这里的除法是向零取整的除法,如 \frac{-5}{2} = -22−5​=−2;
  • and reg val:给储存单元 reg 二进制与上 val 的值;
  • or reg val:给储存单元 reg 二进制或上 val 的值;
  • xor reg val:给储存单元 reg 二进制异或上 val 的值;
  • jmp val 跳转到整个程序第 val 条语句,语句从程序开头开始,用从 11 开始的正整数计数;
  • jz reg val:如果 reg 的值为 00,那么跳转到第 val 行;
  • jnz reg val:如果 reg 的值不为 00,那么跳转到第 val 行;
  • jgz reg val:如果 reg 的值严格大于 00,那么跳转到第 val 行;
  • jsz reg val:如果 reg 的值严格小于 00,那么跳转到第 val 行;
  • read x reg:从远古计算机 xx 读取一个数到储存单元 reg 当中,如果数据线上缓存了一个数字,将读取这个数字并返回,否则等待下个周期再次尝试读取。x = 0x=0 时视为从标准输入数据读取一个数;
  • write val x:将 val 的数值向远古计算机 xx 方向所在数据线写入,当且仅当数据线上没有存有数据才会成功写入,否则等待下个周期再次尝试写入。x = 0x=0 时视为向标准输出数据写出一个数。

reg 表示一个储存单元,只能为 aa 或者 bb 之一。

val 表示一个储存单元或者一个数字的值,比如填入 aa 表示 aa 中储存的值或者填入 233233 表示 233233 这个数字。

一台远古计算机读写指令中 xx 只有与当前远古计算机直接有数据线相连,或者 x=0x=0 才被视为合法指令。

每台远古计算机的标准输入输出独立,远古计算机之间互不影响,即每台远古计算机都有独立的一个标准输入端和一个标准输出端。

每个周期计算时,所有需要执行 write 指令的远古计算机先计算,然后需要执行 read 指令的远古计算机再计算,需要执行其余指令的远古计算机最后计算。

在读取时,如果标准输入数据没有任何可以继续读取的数据,该远古计算机将进入永远等待状态。

一台远古计算机如果执行完了最后一条指令,将会重新从第一条指令开始执行。

如果一台远古计算机没有任何指令,该计算机将永远处于等待状态。

指令计数是从 11 开始的正整数。

一条数据线上最多只能暂存一个数据,两台计算机之间只有一条数据线,即可能读取自己上一轮写入的数据,如果两端的远古计算机同时读取或写入同一条数据线上的 数据,结果将不可预知。

不存在写入标准输入的方法或是从标准输出当中读取数据的方法。

比如如下样例是从 11 号计算机的标准输入读入两个数,并从 22 号计算机的标准输出输出两个数之和。

node 1
read 0 a
read 0 b
write a 2
write b 2
node 2
read 1 a
read 1 b
add a b
write a 0

而以下写法是错误的

node 1
read 0 a
read 0 b
add a b
write a 0
node 2
mov a a

因为正确答案中,一号远古计算机的标准输出为空,而二号远古计算机的标准输出才是两个数之和。

子任务

子任务 1

11 号远古计算机的标准输入将会有不超过 100100 个非负整数,按照原顺序输出到 11 号远古计算机的输出当中。

子任务 2

11 号远古计算机一个非负整数 kk,按照原输入顺序将斐波那契数列第 kk 项输出到 11 号点的标准输出当中,输入数据保证第 kk 项不超过 10^9109。斐波那契数列通项公式为 F_0 = 0, F_1 = 1, F_n = F_{n-1} + F_{n-2}(2 \le n)F0​=0,F1​=1,Fn​=Fn−1​+Fn−2​(2≤n)。

子任务 3

11 号远古计算机的标准输入将会有不超过 100100 个非负整数,按照原顺序输出到 nn 号远古计算机的输出当中。

子任务 4

第 11 到 5050 号远古计算机分别输入 11 个数,将这 5050 个数从 5151 到 100100 号远古计算机输出,输出顺序任意,每个远古计算机输出数字个数任意。

子任务 5

第 11 到 1010 号远古计算机各输入 11 个数,将这些数对应从 100100 到 9191 号远古计算机输出,即 ii 号点输入的数需要从 101 - i101−i 号点输出。

输入格式

这是一道提交答案题,共有 55 组输入数据,这些数据命名为 oldcomputer1.in ~ oldcomputer5.in

这些文件描述了远古计算机之间的连线状态。

文件的第一行是三个非负整数 x,nx,n 和 mm,表示测试点编号、远古计算机的个数与他们之间的连线条数,远古计算机是从 11 到 nn 标号的。

接下来 mm 行,每行两个正整数 x, yx,y,表示计算机 xx 和计算机 yy 之间通过数据线直接相连。

输出格式

对于每组输入数据,你需要提交相应的输出文件 oldcomputer1.out ~ oldcomputer5.out

这些文件描述了每台远古计算机的代码内容。

文件由多个代码块组成,每个代码块的具体格式如下:

第一行为一个字符串 node 与一个 11 到 nn 之间的整数 aa,由一个空格隔开,表示接下来是计算机 aa 的指令。

接下来多行为该计算机的具体指令内容。

每台计算机的指令应当最多出现一次,否则将会出现未知错误。

所有计算机的指令总条数应当不超过 10^6106 行。

输入输出样例

说明/提示

评分方式

对于每个测试点,有三个参数 a_1, a_2, a_3a1​,a2​,a3​。

如果选手提交的代码在 a_1a1​ 个周期内正确输出了答案,将会得到该测试点 100\%100% 的分。
如果选手提交的代码在 a_2a2​ 个周期内正确输出了答案,将会得到该测试点 60\%60% 的分。
如果选手提交的代码在 a_3a3​ 个周期内正确输出了答案,将会得到该测试点 30\%30% 的分。

即在每个周期结束时,会分别进行一次答案正确性判断,以最早正确的一次为准。

子任务分值

子任务编号1122334455
集训队分值10101515151530303030
非集训队分值20202020202020202020

看到题目就晕了

题目就比我前面的两篇文章长。

但仔细看题,好像要用到的就read,write,add,jmp

可我不知道要怎么做

任务1

任务1我借鉴了一小下,发现很简单(是借鉴思路,代码是我敲的!!!)

#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("oldcomputer1.out","w",stdout);
	printf("node 1\nread 0 a\nwrite a 0");
	return 0;
} 

简单吧!

so easy!!

任务2

颜色变了

这个也不会很难

主要是那代码中的代码是什么

这是我的:

#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("oldcomputer1.out","w",stdout);
	printf("node 1\nread 0 a\nadd a 4\njmp a\n");
	return 0;
} 

后面还要有write

这是一个斐波那契数列

需要一个O(1)的代码

#include<bits/stdc++.h>
using namespace std;
int main(){
	freopen("oldcomputer2.out","w",stdout);
	printf("node 1\nread 0 a\nadd a 4\njmp a\n");
	int f[45];
    f[0]=0;f[1]=1;
    for(int i=2;i<=45;i++)
        f[i]=f[i-1]+f[i-2];
    for(int i=0;i<=45;i++)
        printf("write %d 0\n",f[i]);
	return 0;
} 

OK啦!

任务三

不知道这个颜色会不会太淡

任务三不会写

我当然会去借鉴啦

好像要用单路传输

(-。-;)

还是不会

呵呵(哭笑不得)

#include<bits/stdc++.h>
using namespace std;

const int N=110;
vector<int> g[N];
bool inq[N];
int dis[N],pre[N],n,m;

void spfa()
{
    memset(dis,0x3f,sizeof(dis));
    queue<int> q;
    q.push(1);dis[1]=0;
    while(!q.empty())
    {
        int u=q.front();
        for(int v : g[u])
            if(dis[u]+1<dis[v])
            {
                pre[v]=u;
                dis[v]=dis[u]+1;
                if(inq[v]) continue;
                inq[v]=1;q.push(v);
            }
        q.pop();inq[u]=0;
    }
    for(int i=n,nxt=0;i;i=pre[i])
    {
        printf("node %d\n",i);
        printf("read %d a\n",pre[i]);
        printf("write a %d\n",nxt);
        nxt=i;
    }
}

int main()
{
    freopen("oldcomputer3.in","r",stdin);
    freopen("oldcomputer3.out","w",stdout);
    int qwq;
    scanf("%d%d%d",&qwq,&n,&m);
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    spfa();
}

放上答案就对了

这是98版!

在这吃了亏

后面我可能都不会,,ԾㅂԾ,,

#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int> pii;
const int N=1010;
vector<int> g[N];
vector<pii> msg[N];
int dis[N],n,m;
bool inq[N];

void spfa()
{
    queue<int> q;
    memset(dis,0x3f,sizeof(dis));
    for(int i=51;i<=100;i++)
    {
        dis[i]=0;
        inq[i]=1;
        q.push(i);
    }
    while(!q.empty())
    {
        int u=q.front();
        for(int v : g[u])
            if(dis[u]+1<dis[v])
            {
                dis[v]=dis[u]+1;
                if(inq[v]) continue;
                inq[v]=1;q.push(v);
            }
        q.pop();inq[u]=0;
    }
}

int main()
{
    freopen("oldcomputer4.in","r",stdin);
    freopen("oldcomputer4.out","w",stdout);
    int qwq;
    scanf("%d%d%d",&qwq,&n,&m);
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    spfa();
    queue<int> q;
    for(int i=1;i<=50;i++)
    {
        q.push(i);
        msg[i].push_back(pii(0,0));
    }
    while(!q.empty())
    {
        int u=q.front(),v=0;q.pop();
        for(int vv : g[u]) if(dis[u]==dis[vv]+1) v=vv;
        printf("node %d\n",u);
        sort(msg[u].begin(),msg[u].end());
        for(pii pr : msg[u])
        {
            printf("read %d a\n",pr.second);
            printf("write a %d\n",v);
            msg[v].push_back(pii(pr.first+1,u));
        }
        if(v) q.push(v);
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;

const int N=210;
struct MSG{int from,to,time;};
vector<int> g[N];
vector<MSG> msg[N];
bool bad[N][N],inq[N];
int dis[N],pre[N],n,m,ans=0;

bool operator < (const MSG &a,const MSG &b){return a.time<b.time;}

void spfa(int s,int t)
{
    memset(pre,0,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    queue<int> q;q.push(s);
    dis[s]=0;inq[s]=1;
    while(!q.empty())
    {
        int u=q.front();
        for(int v : g[u])
        {
            int w=dis[u]+1;
            while(bad[v][w]||bad[v][w+1]) w++;
            if(w<dis[v])
            {
                dis[v]=w;pre[v]=u;
                if(inq[v]) continue;
                inq[v]=1;q.push(v);
            }
        }
        q.pop();inq[u]=0;
    }
    for(int i=t,nxt=0;i;i=pre[i])
    {
        bad[i][dis[i]]=bad[i][dis[i]+1]=1;
        msg[i].push_back((MSG){pre[i],nxt,dis[i]});
        nxt=i;
    }
    ans=max(ans,dis[t]);
}

int main()
{
    freopen("oldcomputer5.in","r",stdin);
    freopen("oldcomputer5.out","w",stdout);
    int qwq;
    scanf("%d%d%d",&qwq,&n,&m);
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for(int i=1;i<=10;i++) bad[i][0]=bad[i][1]=1;
    for(int i=1;i<=10;i++) spfa(i,101-i);
    for(int i=1;i<=n;i++)
    {
        if(msg[i].empty()) continue;
        sort(msg[i].begin(),msg[i].end());
        printf("node %d\n",i);
        for(MSG pp : msg[i])
        {
            printf("read %d a\n",pp.from);
            printf("write a %d\n",pp.to);
        }
    }
    cerr<<ans+2<<endl;
    return 0;
}

记得关注哦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值