• C2025 基础进阶——模拟与枚举


    (10月来了,CSP也来了,教练布置了一堆基础巩固)

    (也许zzb没有解释清楚,所以可以评论区@)

    (共有10道题,但zzb不想更哩,就三道题吧awa)

    「ABC176E」Bomber

    【题目描述】

    有一个 N*M 的二维矩阵,其中有 M 个目标。第 i 个目标的位置是 (H_iW_i) 。

    你现在有一个炸弹,可以选定一个位置投放炸弹,与炸弹位于同一行或同一列中的爆炸目标将被炸毁。求最多能摧毁多少个目标。

    思路

    思路有手就行(我没手?)

    枚举炸弹放置的位置,判断能够摧毁的目标数量,找出最大值

    时间复杂度为O(HW(H+W))。(TLE自动机)

    考虑优化

    炸弹肯定放在行目标最多列目标最多交点处,统计出行最多的目标数x,列最多的目标数 y。

    那答案就是x+y吗?

    当然不是

    如果x、y的交点上没有数,那肯定就是x+y

    反之,就是x+y-1

    但怎么判断交点上有没有数呢?(总不能O(HW)TLE来求吧)

    我们就可以求有多少个最大行,多少个最大列

    若一个目标处在交点处,那么这个交点就是x+y-1

    如果交点都是x+y-1,答案就是x+y-1,反之就是x+y

    代码如下

    无注释代码

    1. #include
    2. using namespace std;
    3. int h,w,m,mx,my,xx,yy,l,r,cnt,x[300005],y[300005],i;
    4. pair<int,int>q[300005];
    5. int main()
    6. {
    7. scanf("%d%d%d",&h,&w,&m);
    8. for(i=1;i<=m;++i)
    9. {
    10. scanf("%d%d",&l,&r);
    11. ++x[l],++y[r];
    12. q[i]=make_pair(l,r);
    13. }
    14. for(i=1;i<=h;++i)
    15. if(mx
    16. for(i=1;i<=w;++i)
    17. if(my
    18. for(i=1;i<=h;++i)
    19. if(x[i]==mx) ++xx;
    20. for(i=1;i<=w;++i)
    21. if(y[i]==my) ++yy;
    22. for(i=1;i<=m;++i)
    23. if(x[q[i].first]==mx&&y[q[i].second]==my) ++cnt;
    24. printf("%d",mx+my-(cnt==xx*yy));
    25. return 0;
    26. }

    有注释代码

    1. #include
    2. using namespace std;
    3. int h,w,m,mx,my,xx,yy,l,r,cnt,x[300005],y[300005],i;
    4. pair<int,int>q[300005];
    5. int main()
    6. {
    7. scanf("%d%d%d",&h,&w,&m);
    8. for(i=1;i<=m;++i)
    9. {
    10. scanf("%d%d",&l,&r);
    11. ++x[l],++y[r];//记录行上的数量和列上的数量
    12. q[i]=make_pair(l,r);//STL优化码量
    13. }
    14. for(i=1;i<=h;++i)
    15. if(mx//行上最大值
    16. for(i=1;i<=w;++i)
    17. if(my//列上最大值
    18. for(i=1;i<=h;++i)
    19. if(x[i]==mx) ++xx;//有多少行为最大值
    20. for(i=1;i<=w;++i)
    21. if(y[i]==my) ++yy;//有多少列为最大值
    22. for(i=1;i<=m;++i)
    23. if(x[q[i].first]==mx&&y[q[i].second]==my) ++cnt;//有多少个目标处于最大行和最大列的交点上
    24. printf("%d",mx+my-(cnt==xx*yy));//如果满足条件的目标与交点总数相等,就-1,反之不减
    25. return 0;
    26. }

    「ABC129D」Lamp

    【题目描述】

    有一个 H 行 W 列的字符矩阵。

    .表示空地,#表示障碍物。现在可以在.上放一盏灯,光线沿着上下左右传播,遇障碍物停止。问光线最多照亮几个空地。

     思路

    第一思路:模拟plus(其实这道题与上一道题有点像有木有)

    直接TLE自动机

    枚举放的位置,O(HW(H+W))

    然后又来想优化

    枚举肯定没法,只能在计算空地时加大优化

    可以想到(我没想到)用四个数组存储(X,Y)向四个方向的最大连续空地数量

    易证:up[x,y]=up[x-1,y]+1

    同理,别的也可以求出来

    O(HW+HW)

    直接AC

    无注释代码

    1. #include
    2. using namespace std;
    3. int ans,h,w,i,j,f[2001][2001][5];
    4. char s[2001][2001];
    5. int main()
    6. {
    7. scanf("%d%d",&h,&w);
    8. for(i=1;i<=h;i++)
    9. for(j=1;j<=w;j++) cin>>s[i][j];
    10. for(i=1;i<=h;i++)
    11. for(j=1;j<=w;j++)
    12. {
    13. if(s[i][j-1]=='.') f[i][j][1]=f[i][j-1][1]+1;
    14. if(s[i-1][j]=='.') f[i][j][2]=f[i-1][j][2]+1;
    15. }
    16. for(i=h;i>=1;i--)
    17. for(j=w;j>=1;j--)
    18. {
    19. if(s[i][j+1]=='.') f[i][j][3]=f[i][j+1][3]+1;
    20. if(s[i+1][j]=='.') f[i][j][4]=f[i+1][j][4]+1;
    21. if(s[i][j]=='#') continue;
    22. ans=max(f[i][j][1]+f[i][j][2]+f[i][j][3]+f[i][j][4]+1,ans);
    23. }
    24. printf("%d",ans);
    25. return 0;
    26. }

    有注释代码

    1. #include//(感觉其实很像DP)
    2. using namespace std;
    3. int ans,h,w,i,j,f[2001][2001][5];
    4. char s[2001][2001];
    5. int main()
    6. {
    7. scanf("%d%d",&h,&w);
    8. for(i=1;i<=h;i++)
    9. for(j=1;j<=w;j++) cin>>s[i][j];
    10. for(i=1;i<=h;i++)
    11. for(j=1;j<=w;j++)
    12. {
    13. if(s[i][j-1]=='.') f[i][j][1]=f[i][j-1][1]+1;//up
    14. if(s[i-1][j]=='.') f[i][j][2]=f[i-1][j][2]+1;//left
    15. }
    16. for(i=h;i>=1;i--)
    17. for(j=w;j>=1;j--)
    18. {
    19. if(s[i][j+1]=='.') f[i][j][3]=f[i][j+1][3]+1;//down
    20. if(s[i+1][j]=='.') f[i][j][4]=f[i+1][j][4]+1;//right
    21. if(s[i][j]=='#') continue;
    22. ans=max(f[i][j][1]+f[i][j][2]+f[i][j][3]+f[i][j][4]+1,ans);//max
    23. }
    24. printf("%d",ans);
    25. return 0;
    26. }

    「ABC182E」Akari

    【题目描述】

    有一个 H 行 W 列的网格,定义 ( i,j ) 是第 i 行 j 列的方格。

    这个网格上有 N 个灯泡和 M 个障碍物,第 i 个灯泡在 (A_i,B_i) 处,第 i 个障碍物在 (C_i,D_i) 处。每个方格保证最多只有一个灯泡或障碍物。

    每一个灯泡都会将光照向上下左右四个方向延伸,直至遇到障碍物或到达边界。灯泡所在的方格也会有光照。

    请你计算,被光照照到且没有障碍物的方格有多少。

     思路

    (是不是与上一道题叕很像?)

    这道题码量还大一点

    首先,最容易想到的就是TLE思路:

    暴力枚举每一个灯

    比如:

    (画得好丑呀awa)

    但当枚举是,其实是会有重复浪费的部分的,比如(2,3)与(3,2)

    把它拆开看

    其实可以这样遍历(更丑了QWQ)

    实际就是把他拆成四个方向

    对于每一行,从左往右遍历。考虑灯泡往右照射到的空地。

     如果遇到一个灯泡,那么说明此时有光线,标记 flag=1。如果遇到障碍,说明往右的光线被挡住了,flag=0。如果遇到空地,flag 为 1 表示这个空地能够被灯泡照到,进行记录;flag 为 0 表示这个空地不能够被灯泡照到。

    这样,对于每一行,从左往右遍历,可以找出灯泡往右照射到的所有空地。• 按照同样的方式,找出灯泡往左,往上,往下照射到的所有空地。

    时间复杂度为 O(4HW)。

    是不是很绕?

    看代码

    无注释代码

    1. #include
    2. using namespace std;
    3. int n,m,N,M,x,y,f,C,a[1501][1501],i,j;
    4. int main()
    5. {
    6. scanf("%d%d%d%d",&n,&m,&N,&M);
    7. for(i=1;i<=N;i++) scanf("%d%d",&x,&y),a[x][y]=2;
    8. for(i=1;i<=M;i++) scanf("%d%d",&x,&y),a[x][y]=3;
    9. for(i=1;i<=n;i++)
    10. {
    11. f=0;
    12. for(j=1;j<=m;j++)
    13. {
    14. if(a[i][j]==2) f=1;
    15. else if(a[i][j]==3) f=0;
    16. else if(f==1) a[i][j]=1;
    17. }
    18. }
    19. for(i=1;i<=n;i++)
    20. {
    21. f=0;
    22. for(j=m;j>=1;j--)
    23. {
    24. if(a[i][j]==2) f=1;
    25. else if(a[i][j]==3) f=0;
    26. else if(f==1) a[i][j]=1;
    27. }
    28. }
    29. for(i=1;i<=m;i++)
    30. {
    31. f=0;
    32. for(j=1;j<=n;j++)
    33. {
    34. if(a[j][i]==2) f=1;
    35. else if(a[j][i]==3) f=0;
    36. else if(f==1) a[j][i]=1;
    37. }
    38. }
    39. for(i=1;i<=m;i++)
    40. {
    41. f=0;
    42. for(j=n;j>=1;j--)
    43. {
    44. if(a[j][i]==2) f=1;
    45. else if(a[j][i]==3) f=0;
    46. else if(f==1) a[j][i]=1;
    47. }
    48. }
    49. for(i=1;i<=n;i++)
    50. for(j=1;j<=m;j++)
    51. if(a[i][j]==1) C++;
    52. printf("%d",C+N);
    53. }

    有注释代码

    1. #include
    2. using namespace std;
    3. int n,m,N,M,x,y,f,C,a[1501][1501],i,j;
    4. int main()
    5. {
    6. scanf("%d%d%d%d",&n,&m,&N,&M);
    7. for(i=1;i<=N;i++) scanf("%d%d",&x,&y),a[x][y]=2;
    8. for(i=1;i<=M;i++) scanf("%d%d",&x,&y),a[x][y]=3;
    9. //枚举四个方向
    10. for(i=1;i<=n;i++)
    11. {
    12. f=0;
    13. for(j=1;j<=m;j++)
    14. {
    15. if(a[i][j]==2) f=1;//是灯
    16. else if(a[i][j]==3) f=0;//照不到了
    17. else if(f==1) a[i][j]=1;//照得到
    18. }
    19. }
    20. for(i=1;i<=n;i++)
    21. {
    22. f=0;
    23. for(j=m;j>=1;j--)
    24. {
    25. if(a[i][j]==2) f=1;//同上
    26. else if(a[i][j]==3) f=0;
    27. else if(f==1) a[i][j]=1;
    28. }
    29. }
    30. for(i=1;i<=m;i++)
    31. {
    32. f=0;
    33. for(j=1;j<=n;j++)
    34. {
    35. if(a[j][i]==2) f=1;///同上
    36. else if(a[j][i]==3) f=0;
    37. else if(f==1) a[j][i]=1;
    38. }
    39. }
    40. for(i=1;i<=m;i++)
    41. {
    42. f=0;
    43. for(j=n;j>=1;j--)
    44. {
    45. if(a[j][i]==2) f=1;//同上
    46. else if(a[j][i]==3) f=0;
    47. else if(f==1) a[j][i]=1;
    48. }
    49. }
    50. for(i=1;i<=n;i++)
    51. for(j=1;j<=m;j++)
    52. if(a[i][j]==1) C++;//有C个空地被照到了
    53. printf("%d",C+N);//+N个灯
    54. return 0;
    55. }
  • 相关阅读:
    WebGPT VS WebGPU
    哈工大李治军老师操作系统笔记【8】:用户级线程(Learning OS Concepts By Coding Them !)
    【译】Silverlight 不会消亡 XAML for Blazor 到来
    56、springboot ------ RESTful服务及RESTful接口设计
    Mqtt是什么
    HDFS学习笔记(三):HDFS 分布式文件系统原理
    【T3】畅捷通T3采购管理模块反结账,提示:本年数据已经结转,不能取消结账。
    微软确认:测试版用户可在Win11上运行Android应用
    Qt Widget 删除之后还会显示 问题
    Java:JVM架构解释
  • 原文地址:https://blog.csdn.net/weixin_57427186/article/details/133792918