LOJ2984[WC2019]远古计算机(构造)
神仙造计算机题。。。计算机造计算机
subtask 1:
理解了这个题的应该都能写出来。
node 1 read 0 a write a 0
subtask 2:
看到只有一个计算机,内存还只有两个数就明显不能真算了,打表出斐波那契数列,注意要求周期尽量少,所以应该用jmp语句来打表。
1 node 1 2 read 0 a 3 add a 4 4 jmp a
//可以对照行号看一下,a+4行对应的就是相应的第a项 5 write 0 0 6 write 1 0 7 write 1 0 8 write 2 0 9 write 3 0 10 write 5 0 //自己动手丰衣足食 49 write 701408733 0
subtask 3:
在图上bfs,找出1到n的路径,构造即可。
bfs:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<queue> using namespace std; int G[105],to[250],nxt[250],sz=0,pre[105],st[105],sl=-1; bool vis[205]; queue<int> Q; inline void add(int u,int v){ to[++sz]=v;nxt[sz]=G[u];G[u]=sz; to[++sz]=u;nxt[sz]=G[v];G[v]=sz; } int main(){ freopen("oldcomputer3.in","r",stdin); freopen("bfs_res.out","w",stdout); int n,m,i,u,v; bool ok=0; scanf("%d%d%d",&i,&n,&m); while(m--){ scanf("%d%d",&u,&v); add(u,v); } vis[1]=1;Q.push(1); while(!Q.empty()&&!ok){ u=Q.front();Q.pop(); for(i=G[u];i;i=nxt[i])if(!vis[v=to[i]]){ pre[v]=u; if(v==n){ok=1;break;} vis[v]=1; Q.push(v); } } for(;pre[v];v=pre[v])st[++sl]=v; puts("1"); while(sl>=0)printf("%d\n",st[sl--]); return 0; }
构造:(其实两个完全可以写在一起,懒得改了)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> int a[105]; int main(){ freopen("bfs_res.out","r",stdin); freopen("oldcomputer3.out","w",stdout); int i,x,m=0; while(scanf("%d",&x)==1)a[++m]=x; for(i=1;i<=m;++i)printf("node %d\nread %d a\nwrite a %d\n",a[i],a[i-1],a[i+1]); return 0; }
subtask 4:
从51~100号点往回跑最短路,可以发现1~50号点的距离都不超过3,这就提示我们可以根据距离递减来构造方案。
然而dfs构造的方案只能拿60%的分,周期太多了,于是我们乱搞一下:对于每个中转,记录下它之前有几个点,每个结点输出的时候贪心地选前面结点最少的中转先输出就AC了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; int G[1005],to[4000],nxt[4000],sz=0,d[1005],n; queue<int> Q; struct opt{ int r,w,t; opt(){} opt(int r,int w,int t):r(r),w(w),t(t){} }; vector<opt> V[1005]; inline bool cmp(opt a,opt b){return a.t<b.t;} inline void add(int u,int v){ to[++sz]=v;nxt[sz]=G[u];G[u]=sz; to[++sz]=u;nxt[sz]=G[v];G[v]=sz; } void dfs(int u,int fa,int t){ if(u>50&&u<=100){ V[u].push_back(opt(fa,0,t)); return; } int i,v; for(i=G[u];i;i=nxt[i])if(d[v=to[i]]==d[u]-1&&V[v].size()<3){ V[u].push_back(opt(fa,v,t)); dfs(v,u,t+1); return; } } int main(){ freopen("oldcomputer4.in","r",stdin); freopen("oldcomputer4.out","w",stdout); int m,i,j,u,v; scanf("%d%d%d",&i,&n,&m); while(m--){ scanf("%d%d",&u,&v); add(u,v); } memset(d,0x3f,sizeof(d)); for(i=51;i<=100;++i){ d[i]=0; Q.push(i); } while(!Q.empty()){ u=Q.front();Q.pop(); for(i=G[u];i;i=nxt[i])if(d[v=to[i]]==0x3f3f3f3f){ d[v]=d[u]+1; Q.push(v); } } for(i=1;i<=50;++i)dfs(i,0,0); for(i=1;i<=1000;++i)if(!V[i].empty()){ printf("node %d\n",i); sort(V[i].begin(),V[i].end(),cmp); for(j=0;j<V[i].size();++j)printf("read %d a\nwrite a %d\n",V[i][j].r,V[i][j].w); } return 0; }
subtask 5:
这回要认真一点乱搞了。。。用$used_{u,t}$记下$u$在$t$时刻是不是有事做,那么$v$开始中转的时间$d_v$定为最小的$t$使得$t>d_u$且$used_{v,t}$,$used_{v,t+1}$均为$false$。跑10次$Dijkstra$即可。
事实证明邻接表存图60%,vector存图100%,实在不放心可以random_shuffle一下。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; int d[105],pre[105]; bool used[105][25]; vector<int> G[105]; struct node{ int p,d; node(){} node(int p,int d):p(p),d(d){} inline bool operator <(const node &b)const{return d>b.d;} }; priority_queue<node> Q; struct opt{ int r,w,t; opt(){} opt(int r,int w,int t):r(r),w(w),t(t){} }; vector<opt> V[105]; inline bool cmp(opt a,opt b){return a.t<b.t;} inline void dijkstra(int s,int t){ int i,u,v,dis=1,lst=0; node h; memset(d,0x3f,sizeof(d)); while(!Q.empty())Q.pop(); while(used[s][dis]||used[s][dis+1])++dis; Q.push(node(s,d[s]=dis)); while(!Q.empty()){ h=Q.top();Q.pop(); if(d[u=h.p]!=h.d)continue; if(u==t)break; for(i=0;i<G[u].size();++i){ v=G[u][i];dis=d[u]+1; while(used[v][dis]||used[v][dis+1])++dis; if(dis<d[v]){ pre[v]=u; Q.push(node(v,d[v]=dis)); } } } v=t; while(v!=s){ used[v][d[v]]=used[v][d[v]+1]=1; V[v].push_back(opt(pre[v],lst,d[v])); v=pre[lst=v]; } used[s][d[s]]=used[s][d[s]]=1; V[s].push_back(opt(0,lst,d[s])); } int main(){ freopen("oldcomputer5.in","r",stdin); freopen("oldcomputer5.out","w",stdout); int n,m,i,j,u,v; scanf("%d%d%d",&i,&n,&m); while(m--){ scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } for(i=1;i<=10;++i)dijkstra(i,101-i); for(i=1;i<=100;++i)if(!V[i].empty()){ printf("node %d\n",i); sort(V[i].begin(),V[i].end(),cmp); for(j=0;j<V[i].size();++j)printf("read %d a\nwrite a %d\n",V[i][j].r,V[i][j].w); } return 0; }