20181027解题报告

模拟赛越打越少,有点伤感,但还是记录下这最后几场。

梦想总是遥不可及,是不是应该放弃。

 T1:上海红茶馆 ChineseTea.cpp
问题描述:
你现在正在经营一家红茶馆, 而且这里有各种各样的红茶, 你现在把这些红茶分成了N个等级, 每个等级的茶有一个品质Q。
现在每一个来的客人都会要求一个品质为S的茶, 你需要迅速的回答他是否有。

输入格式:
第一行两个数N,M。
下面一行N个数, 分别表示每个等级的茶的品质Q。
下面一行M个数, 分别表示询问的品质S。

输出格式:
输出一行M个字符, 表示回答是否。 Y表示有, N表示没有。

样例输入:
5 5
1 3 4 6 8
1 2 3 4 5
样例输出:
YNYYN

数据规模:
30%:N,M<5000
100%:N,M<200000
据说c++map一下就解决了~~但由于ywd垃圾的评测机被卡成60~~ 没有map的c选手只好先快排再写个二分查找。附上代码:
`

#include<stdio.h>
#include<stdlib.h>
FILE*fin,*fout;
int a[200050]={0};
int n,m,flag=0;
int binsearch(int left,int right,int goal)
{
    int mid;
    mid=(left+right)/2;
    if(a[mid]==goal)
      {
      flag=1;
      return 0;
      }
    if(flag==1||left>=right)  return 0;
    if(a[mid]>goal)  {binsearch(left,mid-1,goal);}
    else if(a[mid]<goal)  {binsearch(mid+1,right,goal);}
    return 0;
}
int quicksort(int left,int right)
{
    int i,j,mid,t;
    i=left;j=right;mid=a[(i+j)/2];
    while(i<=j)
      {
      while(a[i]<mid)  i++;
      while(a[j]>mid)  j--;
      if(i<=j)
        {
        t=a[i];a[i]=a[j];a[j]=t;
        i++;j--;
        }
      }
    if(i<right)  quicksort(i,right);
    if(j>left)   quicksort(left,j);
    return 0;
}
int main()
{
    int x,i;
    fin=fopen("chinesetea.in","r");
    fout=fopen("chinesetea.out","w");
    fscanf(fin,"%d%d",&n,&m);
    for(i=1;i<=n;i++)
      fscanf(fin,"%d",&a[i]);
    quicksort(1,n);
    for(i=1;i<=m;i++)
      {
      flag=0;
      fscanf(fin,"%d",&x);
      binsearch(1,n,x);
      if(flag==1)
        fprintf(fout,"Y");
      else fprintf(fout,"N");
      }
    fclose(fin);
    fclose(fout);
    return 0;
}

T2:

软件安装  install.cpp

问题描述:

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
    但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
    我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

Input

第1行:N, M  (0<=N<=100, 0<=M<=500)
  第2行:W1, W2, ... Wi, ..., Wn (0<=Wi<=M )
  第3行:V1, V2, ..., Vi, ..., Vn  (0<=Vi<=1000 )
  第4行:D1, D2, ..., Di, ..., Dn (0<=Di<=N, Di≠i )

Output

一个整数,代表最大价值。

Sample Input

3 10
5 5 6
2 3 4
0 1 1

 

Sample Output

5

这个题难度对我这种蒟蒻实在太高了,我一开始一看觉得是个背包,想把有依赖条件的物品创造出一个新的物品,推了半天没推出来,然后从网络流的角度想,构一个终极源点和终极汇点在里面跑一个总体积小于m的最大流由于网络流写炸而且这玩意最后听说可能和费用流这种我不会的东西有关。最后强打暴力O(2^n)加一通玄学剪枝40分。正解应是tarjan缩点(防止循环依赖)然后再跑树形dp。附上惨不忍睹的暴力代码:

#include<stdio.h>
#include<stdlib.h>
FILE*fin,*fout;
int v[100001]={0},w[100001]={0},vis[100001]={0},fa[100001]={0},used[100001]={0};
int n,m,ans=-1,vsum=0;
int judge()
{
    int i,sum=0;
    for(i=1;i<=n;i++)
      if(fa[i]==0&&vis[i]==1)
        {
        sum+=w[i];
        }
      else if(vis[i]==1)
        {
        if(used[fa[i]]==1)
          {
          used[i]=1;
          sum+=w[i];
          }
        }
    if(sum>ans)  ans=sum;
    return 0;
}
int dfs(int i)
{
    if(vsum>m)
      return 0;
    if(i==n+1)
      {
      judge();
      return 0;
      }
    vis[i]=1;
    if(fa[i]==0||used[fa[i]]==1)
      used[i]=1;
    vsum+=v[i];
    if(used[i]==1)
      dfs(i+1);
    vsum-=v[i];
    used[i]=0;
    vis[i]=0;
    dfs(i+1);
    return 0;
}
int main()
{
    int i,j;
    fin=fopen("install.in","r");
    fout=fopen("install.out","w");
    fscanf(fin,"%d%d",&n,&m);
    for(i=1;i<=n;i++)
      fscanf(fin,"%d",&v[i]);
    for(i=1;i<=n;i++)
      fscanf(fin,"%d",&w[i]);
    for(i=1;i<=n;i++)
      fscanf(fin,"%d",&fa[i]);
    dfs(1);
    fprintf(fout,"%d",ans);
    fclose(fin);
    fclose(fout);
    return 0;
}

T3:乘电梯

 一道区间dp,我也懒得看了,直接敲暴力,50分。今年noip我肯定会因为dp不擅长吃很多亏。

#include<stdio.h>
#include<stdlib.h>
FILE*fin,*fout;
double time[100001]={0};
int s[100001]={0},t[100001]={0},vis[100001]={0};
double ans=214748361,sum=0;
int n,m;
double cal(double a,double b)
{
    return (a*(a+1)+b*(b+1))/(2*(a+b+1));
}
int dfs(int fnum)
{
    int i;
    if(sum+m-1>ans)  return 0;
    if(time[fnum]<sum&&time[fnum]!=0)
      return 0;
    if(time[fnum]==0)
      time[fnum]=sum;
    if(fnum==1)
      {
      if(sum+m-1<ans)
        ans=sum+m-1;
      return 0;
      }
    for(i=1;i<=n;i++)
      {
      if(fnum>t[i])  break;
      if(fnum<=t[i]&&fnum>=s[i]&&vis[i]==0)
        {
        sum+=cal(t[i]-fnum,fnum-s[i]);
        vis[i]=1;
        dfs(s[i]);
        vis[i]=0;
        sum-=cal(t[i]-fnum,fnum-s[i]);
        }
      }
    return 0;
}
int quicksort(int left,int right)
{
    int i,j,mid,t1;
    i=left;j=right;mid=t[(i+j)/2];
    while(i<=j)
      {
      while(t[i]>mid)  i++;
      while(t[j]<mid)  j--;
      if(i<=j)
        {
        t1=t[i];t[i]=t[j];t[j]=t1;
        t1=s[i];s[i]=s[j];s[j]=t1;
        i++;j--;
        }
      }
    if(i<right)  quicksort(i,right);
    if(j>left)   quicksort(left,j);
    return 0;
}
int main()
{
    int i;
    fin=fopen("lifts.in","r");
    fout=fopen("lifts.out","w");
    fscanf(fin,"%d%d",&n,&m);
    for(i=1;i<=n;i++)
      fscanf(fin,"%d%d",&s[i],&t[i]);
    quicksort(1,n);
    dfs(m);
    fprintf(fout,"%.5lf",ans);
    fclose(fin);
    fclose(fout);
    return 0;
}

T4:

暗夜骑士  NightOfKnights.cpp

问题描述:

你现在负责管理骑士, 也就是负责城堡的守卫工作。

现在告诉你一个N*M的矩阵, 上面有一些位置有骑士, 有一个位置有入侵者, 还有一个位置是城堡的入口。骑士每一个单位时间, 都会扩展一格视野。 假设骑士在x,y, 那么在时间t, 任意格子i,j,只要满足|x-i|+|y-j|<=t, 那么这些格子上的入侵者都是可以发现的。入侵者每一个单位时间最多可以走一步(可以不走, 方向为上下左右中的一个)。

一旦入侵者被发现就会逃走, 如果在城堡入口被发现了, 也会逃走。你只需要回答最多有多少入侵者可能进入。

输入格式:

第一行4个整数, N,M

下面N行M列的整数描述题中的矩阵, 0表示空地, 1表示骑士, 2表示入侵者, 3表示城堡入口。

输出格式:

输出一行一个整数, 表示最多有多少入侵者可能进入。

样例输入:

6 5

0 0 3 0 0

0 2 0 0 0

0 0 2 0 1

0 0 1 0 0

1 0 0 0 0

0 0 0 2 0

样例输出:

2

数据规模:

40%:N,M 不超过 100, 入侵者和骑士都不超过10

100%: 所有数字不超过1000, 包括骑士数量, 入侵者数量。

这道题名字没有翻成黑暗骑士真是很遗憾了。我用了一个贪心的想法,假如你一个入侵者到城堡的距离>=离城堡最近的骑士的距离,那有请下一位入侵者。粗算一下复杂度觉得怎么写都ok就写了个最原始的三次循环于是就是众人中跑的最慢的,附上代码:

#include<math.h>
#include<stdio.h>
#include<stdlib.h>
FILE*fin,*fout;
int w[1005][1005]={0};
int n,m,cx,cy,ans=0,min=2147483631;
int main()
{
    int i,j;
    fin=fopen("nightofknights.in","r");
    fout=fopen("nightofknights.out","w");
    fscanf(fin,"%d%d",&n,&m);
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        {
        fscanf(fin,"%d",&w[i][j]);
        if(w[i][j]==3)
          {
          cx=i;
          cy=j;
          }
        }
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        if(w[i][j]==1)
          {
          if(abs(cx-i)+abs(cy-j)<min)
            min=abs(cx-i)+abs(cy-j);
          }
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        if(w[i][j]==2)
          if(abs(cx-i)+abs(cy-j)<min)
            ans++;
    fprintf(fout,"%d",ans);
    fclose(fin);
    fclose(fout);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值