day2018.6.23模拟赛总结

匿名 (未验证) 提交于 2019-12-03 00:34:01

emmm...今天的题考的不是很好,T2莫名挂机.

T1:

题目大意:以最简分数的形式给出一个时钟上时针与分针的夹角,时针与秒针的夹角,分针与秒针的夹角,求出所有满足条件的时间.

emmm...大水题,直接暴力枚举用double存分数水过.

考场AC代码:

#include<bits/stdc++.h>   using namespace std; #define ACF inline void typedef long long LL; typedef double LD; const LD eps=0.0000001; int a1,b1,a2,b2,a3,b3,T,s,h,m,sum; LD x,y,z; struct node{   int x,y,z; }q[1000000]; ACF into(){   scanf("%d/%d%d/%d%d/%d",&a1,&b1,&a2,&b2,&a3,&b3);   x=1.0*a1/b1;y=1.0*a2/b2;z=1.0*a3/b3; } bool is(double a,double b){   if (fabs(a-b)<=eps) return true;   else return false; } bool check(int a,int b,int c){   LD a1,a2,a3;   a3=c*6.0;   a2=b*6.0+c*0.1;   a1=a*30.0+b*0.5+c*(0.5/60.0);    if ((is(fabs(a1-a2),x)||is(360.0-fabs(a1-a2),x))&&(is(fabs(a1-a3),y)||is(360.0-fabs(a1-a3),y))&&(is(fabs(a2-a3),z)||is(360.0-fabs(a2-a3),z))) return true;   else return false; } ACF work(){   sum=0;   for (h=0;h<12;h++)     for (m=0;m<60;m++)       for (s=0;s<60;s++)         if (check(h,m,s))           q[++sum].x=h,q[sum].y=m,q[sum].z=s; } ACF outo(){   printf("%d\n",sum);   for (int i=1;i<=sum;i++){     if (q[i].x<10) printf("0");     printf("%d",q[i].x);     putchar(':');     if (q[i].y<10) printf("0");     printf("%d",q[i].y);     putchar(':');     if (q[i].z<10) printf("0");     printf("%d",q[i].z);     putchar('\n');   } } int main(){   //freopen("clock.in","r",stdin);   //freopen("clock.out","w",stdout);   scanf("%d",&T);   while (T--){     into();     work();     outo();   }   return 0; }

T2:

题目大意:

有一张n个点m条边的无向图,点从1到n编号,边权均为1.

定义一条路径为另一条一条路径的路径子序列,当且仅当以下两条件同时满足:

1、起始点与终点和另一条路径一样.

2、当前序列是的另一条路径的子序列.

现在,给定一条从点1到点n的路径,你的任务就是找到该路径中点数最少的路径子序列,为了方便,你只需要输出它的长度即可.

这道题用O(n)或O(nlog(n))的算法做就可以了.

考场上我想了一个DP,思路是这样的:

由于边都是双向边,也就是说我们可以双向行走,而题目要求的是子序列,所以我们只要存的非原始路径边(x,y)只有当x和y都在原始路径中才要存,求存的时候应与原始路径的顺序相同.

然后我们就可以用f[i]表示走到原始路径上第i个点的最短路径长度.

那么考场40分代码如下:

#include<bits/stdc++.h>   using namespace std; #define ACF inline void const int N=50000; const int M=200000;  int n,m,k,a[N+1],f[N+1],wh[N+1],top; struct seg{   int l,r; }e[M+1]; ACF into(){   top=0;    scanf("%d%d%d",&n,&m,&k);   int x,y;   for (int i=1;i<=k+1;i++){     scanf("%d",&x);     wh[x]=i;   }   for (int i=1;i<=m-k;i++){     scanf("%d%d",&x,&y);     if (!wh[x]||!wh[y]) continue;     if (wh[x]>wh[y]) swap(x,y);     e[++top].l=wh[x];e[top].r=wh[y];   } } bool cmp(seg a,seg b){   return a.r<b.r; } ACF work(){   sort(e+1,e+1+top,cmp);   int j=1;   for (int i=2;i<=k+1;i++){     f[i]=f[i-1]+1;     for (;e[j].r==i;j++)       f[i]=min(f[i],f[e[j].l]+1);   } } ACF outo(){   printf("%d\n",f[k+1]); } int main(){   //freopen("seqpath.in","r",stdin);   //freopen("seqpath.out","w",stdout);   int T;   scanf("%d",&T);   while (T--){     into();     work();     outo();   }   return 0; }

DP莫名错误不知所措...

突然发现自己忘了清空数组...

改完AC代码如下:

#include<bits/stdc++.h>   using namespace std; #define ACF inline void const int N=50000; const int M=200000;  int n,m,k,f[N+1],wh[N+1],top; struct seg{   int l,r; }e[M+1]; ACF into(){   memset(wh,0,sizeof(wh));   memset(f,0,sizeof(f));   top=n=m=k=0;   memset(e,0,sizeof(e));   scanf("%d%d%d",&n,&m,&k);   int x,y;   for (int i=1;i<=k+1;i++){     scanf("%d",&x);     wh[x]=i;   }   for (int i=1;i<=m-k;i++){     scanf("%d%d",&x,&y);     if (x==y) continue;     if (!wh[x]||!wh[y]) continue;     if (wh[x]>wh[y]) swap(x,y);     e[++top].l=wh[x];e[top].r=wh[y];   } } bool cmp(seg a,seg b){   return a.r<b.r; } ACF work(){   sort(e+1,e+1+top,cmp);   int j=1;   f[1]=0;   for (int i=2;i<=k+1;i++){     f[i]=f[i-1]+1;     for (;e[j].r==i;j++)       f[i]=min(f[i],f[e[j].l]+1);   } } ACF outo(){   printf("%d\n",f[k+1]); } int main(){   //freopen("seqpath.in","r",stdin);   //freopen("seqpath.out","w",stdout);   int T;   scanf("%d",&T);   while (T--){     into();     work();     outo();   }   return 0; }

T3:

题目大意:

平面上有n个人,每个人所在的位置可以用一个坐标(x,y)表示,其中x,y均为整数,一个人每次可以选择上下左右任意一个方向走一步,其代价为1,即(x,y)可以变为(x+1,y)、(x-1,y)、(x,y-1)、(x,y+1).

同时,定义一个位置集S是连通的当且仅当S中的任意两个位置都可以只经过S中的位置互相到达.

给定n个人所在的坐标,求使得n个人所在位置两两不同,且所在的位置集合连通的最小总代价.

一看不会,果断放弃.

推了一通n<=3的情况最终放弃.

正解是各种用贪心去中位数然后暴力枚举在这个中位数附近.

具体各类操作看每个函数的含义.

AC代码如下:

#include<bits/stdc++.h>   using namespace std; #define ACF inline void typedef long long LL; const int x_[4]={0,1,0,-1},y_[4]={1,0,-1,0}; const int N=6; const LL INF=10000000000000000; int n,mx,my,px[N+5],py[N+5],fx[N+5],fy[N+5],ex[N*4+5],ey[N*4+5]; bool v[N*3+5][N*3+5]; //mx,my分别表示横纵坐标的中位数,fx,fy数组表示每个人所在的原始横纵坐标 //px,py分别表示每个人要到达的终点位置的坐标,ex,ey分别表示终点枚举的几个可供选择的点  void mid(){      //取横坐标的中位数与纵坐标的中位数    int x[N+5],y[N+5],u=(n+1)/2,d=n/2+1;   for (int i=1;i<=n;i++)     x[i]=fx[i],y[i]=fy[i];   sort(x+1,x+1+n);sort(y+1,y+1+n);   mx=(x[u]+x[d])/2;my=(y[u]+y[d])/2; } LL calc(){      //暴力枚举排列判断哪个位置匹配哪个人    int per[N+5]={0};   LL ans=INF;   for (int i=1;i<=n;i++) per[i]=i;   do{      //用do-while是因为while(next_permutation)会跳过初始序列      LL s=0LL;     for (int i=1;i<=n;i++)       s+=abs(fx[per[i]]-px[i])+abs(fy[per[i]]-py[i]);      //计算当前情况下的行走步数      ans=min(ans,s);   }while (next_permutation(per+1,per+1+n));      //枚举全排列    return ans; } LL Try(int t,int s,int e){   if (t>n) return calc();   LL ans=INF;   for (int i=s;i<=e;i++){     px[t]=ex[i];py[t]=ey[i];      //暴力枚举确定终点位置     int ne=e;     for (int d=0;d<4;d++)       if (!v[px[t]+x_[d]+N][py[t]+y_[d]+N]){      //若这个点未被占领         ex[++ne]=px[t]+x_[d],ey[ne]=py[t]+y_[d];         v[ex[ne]+N][ey[ne]+N]=1;       }      //暴力打标记      ans=min(ans,Try(t+1,i+1,ne));      //往下递归      for (int i=e+1;i<=ne;i++)       v[ex[i]+N][ey[i]+N]=0;      //回溯    }   return ans; } ACF into(){   mx=my=0;   memset(px,0,sizeof(px));   memset(py,0,sizeof(py));   memset(fx,0,sizeof(fx));   memset(fy,0,sizeof(fy));   //初始化清空数组   scanf("%d",&n);   for (int i=1;i<=n;i++)     scanf("%d%d",&fx[i],&fy[i]);   mid(); } ACF work(){   for (int i=1;i<=n;i++)     fx[i]-=mx,fy[i]-=my;      //计算到中位数的需要的偏移量    v[N][N]=1;   for (int i=1;i<=4;i++){     ex[i]=x_[i-1],ey[i]=y_[i-1];      //枚举4个点每个终点位置      v[ex[i]+N][ey[i]+N]=1;   } } ACF outo(){   printf("%lld\n",Try(2,1,4));      //dfs暴力求解  } int main(){   //freopen("meet.in","r",stdin);   //freopen("meet.out","w",stdout);    int T;   scanf("%d",&T);   while (T--){     into();     work();     outo();   }   return 0; }

又是一道码农题...

转载请标明出处:day2018.6.23模拟赛总结
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!