欢乐赛解题报告

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了欢乐赛解题报告相关的知识,希望对你有一定的参考价值。

~~一场不欢乐的欢乐赛

时间分配::T1做的时候还可以,大约三十分钟写了个深搜(鬼知道我为啥不用广搜,大概是因为快半个月没写了)写完后去研究第二题,刚开始以为是贪心,很快写了出来,但是自己推了一会举出了反例。于是自己想了很多方法,但是都是基于贪心,写了一个多小时,写炸了,没办法又改成了贪心。第三题并不会,然后搜索大法过了一个点,(输出-1也是一个点)

整体感觉::还是太弱,T1是会的,但是还是没做对,大概是独立做题少的缘故吧,平常做题都没有思考太多时间。T2贪心T3暴力,貌似自己啥都不会。到现在第三题好像快要放弃了,题解一点也,看不懂。

题目解析::

T1::

水灾(sliker.cpp/c/pas) 1000MS  64MB

大雨应经下了几天雨,却还是没有停的样子。土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没。

CCY所在的城市可以用一个N*M(N,M<=50)的地图表示,地图上有五种符号:“. * X D S”。其中“X”表示石头,水和人都不能从上面经过。“.”表示平原,CCY和洪水都可以经过。“*”表示洪水开始地方(可能有多个地方开始发生洪水)。“D”表示CCY的别墅。“S”表示CCY现在的位置。

CCY每分钟可以向相邻位置移动,而洪水将会在CCY移动之后把相邻的没有的土地淹没(从已淹没的土地)。

求CCY回到别墅的最少时间。如果聪哥回不了家,就很可能会被淹死,那么他就要膜拜黄金大神涨RP来呼叫直升飞机,所以输出“ORZ hzwer!!!”。

----------------------------------------------------------------------------------------------------------------------

洪水的强化的强化版,关键处在于人在走第不同的步数时洪水的状态时不同的,在走相同步数时洪水的状态是相同的。通过这个我们可以先推导出人在走第n步时的洪水状态。之后

广搜,条件是下一步要走到的位置洪水没有覆盖且没走过且是‘。’的点。

第一遍做时用的深搜,半个月没写广搜了,思维惯性,T了6个点

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

char map[1500][61][61];

bool hsvisited[61][61];

bool renvisited[61][61];

int xgo[4]={1,-1,0,0};

int ygo[4]={0,0,1,-1};

int nowx;int nowy;int fx;int fy;int n;int m;int ans=0x7ffffff;

void dfs(int step,int x,int y)

{

       //if(map[step][x][y]==‘*‘)return;//合理化剪枝 算了放循环里吧

       if(x==fx&&y==fy)

       {

              ans=min(step,ans);

              return;

       }

       if(step>ans)return; //最优化剪枝

       for(int i=0;i<4;i++)

       {

              int xn=x+xgo[i];

              int yn=y+ygo[i];

              if(!renvisited[xn][yn]&&(map[step+1][xn][yn]==‘.‘||map[step+1][xn][yn]==‘D‘))

              {

                     renvisited[xn][yn]=true;

                     dfs(step+1,xn,yn);

                     renvisited[xn][yn]=false;

              }

       }

}

int main()

{

       freopen("sliker.in","r",stdin);

       freopen("sliker.out","w",stdout);

       cin>>n>>m;

       for(int i=1;i<=n;i++)

         for(int j=1;j<=m;j++)

         {

             cin>>map[0][i][j];

             if(map[0][i][j]==‘S‘)

             {

                    nowx=i;

                    nowy=j;

                    map[0][i][j]=‘.‘;

                    renvisited[i][j]=true;

             }

             if(map[0][i][j]==‘D‘)

             {

                    fx=i;fy=j;

             }

         }

       for(int z=1;z<=1300;z++)     //离线处理 //jiduanqingkuangbukaolvle chutiren meinamewuliao

       {

              //bool flag=false;

              memset(hsvisited,0,sizeof(hsvisited));

              for(int i=1;i<=n;i++)

              for(int j=1;j<=m;j++)

              {

                    

                     if(map[z-1][i][j]==‘*‘)

                     {

                            for(int op=0;op<4;op++)

                            {

                                   int xn=i+xgo[op];

                                   int yn=j+ygo[op];

                                   if(map[z-1][xn][yn]==‘.‘)

                                   {

                                          hsvisited[xn][yn]=1;

                                          //flag=true;     这个不能加

                                   }

                                  

                            }

                     }

                     map[z][i][j]=map[z-1][i][j];

              }

              //if(!flag)break;

              for(int i=1;i<=n;i++)

              for(int j=1;j<=m;j++)

              {

                     if(hsvisited[i][j])

                       map[z][i][j]=‘*‘;

              }

       }

       dfs(0,nowx,nowy);

       if(ans==0x7ffffff)

         printf("ORZ hzwer!!!");

       else

         printf("%d",ans);

       fclose(stdin);

       fclose(stdout);

       return 0;

}

/*

3 3

D.*

...

.S.

*/

/*

3 3

D.*

...

..S

*/

/*

3 6

D...*.

.X.X..

....S.

3 3

D..

...

..S

*/

第二遍做的时候在原来基础上改成了广搜,就可以了

#include<queue>

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

struct note

{int x;int y;int step;};

char map[1500][61][61];

bool hsvisited[61][61];

bool renvisited[61][61];

int xgo[4]={1,-1,0,0};

int ygo[4]={0,0,1,-1};

int nowx;int nowy;int fx;int fy;int n;int m;

queue<note>q;

int main()

{

       freopen("sliker.in","r",stdin);

       freopen("sliker.out","w",stdout);

       cin>>n>>m;

       for(int i=1;i<=n;i++)

         for(int j=1;j<=m;j++)

         {

             cin>>map[0][i][j];

             if(map[0][i][j]==‘S‘)

             {

                    nowx=i;

                    nowy=j;

                    map[0][i][j]=‘.‘;

                    renvisited[i][j]=true;

             }

             if(map[0][i][j]==‘D‘)

             {

                    fx=i;fy=j;

             }

         }

       for(int z=1;z<=1300;z++)     //离线处理 //jiduanqingkuangbukaolvle chutiren meinamewuliao

       {

              memset(hsvisited,0,sizeof(hsvisited));

              for(int i=1;i<=n;i++)

              for(int j=1;j<=m;j++)

              {

                    

                     if(map[z-1][i][j]==‘*‘)

                     {

                            for(int op=0;op<4;op++)

                            {

                                   int xn=i+xgo[op];

                                   int yn=j+ygo[op];

                                   if(map[z-1][xn][yn]==‘.‘)

                                   {

                                          hsvisited[xn][yn]=1;

                                   }

                                  

                            }

                     }

                     map[z][i][j]=map[z-1][i][j];

              }

              for(int i=1;i<=n;i++)

              for(int j=1;j<=m;j++)

              {

                     if(hsvisited[i][j])

                       map[z][i][j]=‘*‘;

              }

       }

       note zz;

       zz.x=nowx;

       zz.y=nowy;

       zz.step=0;

       q.push(zz);

       while(!q.empty())

       {

              note op=q.front();

              q.pop();

              for(int i=0;i<4;i++)

              {

                     int xn=op.x+xgo[i];

                     int yn=op.y+ygo[i];

                     int s=op.step;

                     if((map[s+1][xn][yn]==‘.‘||map[s+1][xn][yn]==‘D‘)&&!renvisited[xn][yn])

                     {

                            renvisited[xn][yn]=1;

                            note iq;

                            iq.x=xn;

                            iq.y=yn;

                            iq.step=s+1;

                            if(xn==fx&&yn==fy)

                            {

                                   printf("%d",iq.step);

                                   return 0;

                            }

                            q.push(iq);

                     }

              }

             

       }

       printf("ORZ hzwer!!!");

       fclose(stdin);

       fclose(stdout);

       return 0;

}

 

 

T2某种数列问题  (jx.cpp/c/pas) 1000MS 256MB

众所周知,chenzeyu97有无数的妹子(阿掉!>_<),而且他还有很多恶趣味的问题,继上次纠结于一排妹子的排法以后,今天他有非(chi)常(bao)认(cheng)真(zhe)去研究一个奇怪的问题。有一堆他的妹子站成一排,然后对于每个妹子有一个美丽度,当然美丽度越大越好,chenzeyu97妹子很多,但是质量上不容乐观,经常出现很多美丽度为负数的妹子(喜闻乐见),chenzeyu97希望从一排妹子里找出3队连续的妹子,使她们的美丽度和最大。注意,一个妹子不能被编入多个队伍而且一定要拿出三队,不然czy会闲着没事做~。

简单滴说就是:

给定一个数列,从中找到3个无交集的连续子数列使其和最大。

【输入文件】

第一行一个数n,表示数列长度。

接下来有n行,每行一个数,第i行为第i个数。

【输出文件】

仅有一个数,表示最大和。

方法::假如在做单一的最大子段和的问题时用的dp解法而不是贪心,做这个题就会容易得多。毕竟只是多了一个条件。

状态::f【i】【j】【flag】表示到第i个数选了j段妹子并且当前数是否要选的状态

#include<cstdio>

#include<algorithm>

using namespace std;

int note[1000001];

int dp[4][1000001][2];

int read()

{

       int f=1;

       int num=0;

       char c=getchar();

       while(c<‘0‘||c>‘9‘){

              if(c==‘-‘)f=-1;

              c=getchar();

       }

       while(c>=‘0‘&&c<=‘9‘)

       {

              num*=10;

              num+=c-‘0‘;

              c=getchar();

       }

       return f*num;

}

int main()

{

       freopen("jx.in","r",stdin);

       freopen("jx.out","w",stdout);

       int n=read();

       for(int i=1;i<=n;i++)

       {

              note[i]=read();

       }

       for(int i=1;i<=n;i++)

       {

              for(int j=1;j<=3;j++)

              {

                    

                     dp[j][i][0]=max(dp[j][i-1][0],dp[j][i-1][1]);

                     /*既然当前的的不拿,最大值就和当前无关,只需要判断前一步的最大值*/

                     dp[j][i][1]=max(dp[j][i-1][1]+note[i],max(dp[j][i][1],dp[j-1][i-1][0]+note[i]));

                     /*当前的若要拿的话   分两种情况*/

                     /*与上一个连着  单成一个*/

                     /*但是如果这两种情况都小于0时还不如不选*/

              }

       }

       printf("%d",max(dp[3][n][1],dp[3][n][0]));

       return 0;

}

但是,在考试时这个题想不出来dp的方法,就跑了三遍贪心,竟然过了6个点

#include<cstdio>//本来打算用一种贪心+排序。。。算了,贪心三遍吧 我也知道不对万一碰上呢

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

int shuru[1000001];

bool visited[1000001];

int ans=0;

int n,top=0;

int read()

{

       int f=1;

       int now=0;

       char c=getchar();

       while(c<‘0‘||c>‘9‘)

       {

              if(c==‘-‘)f=-1;

              c=getchar();

       }

       while(c>=‘0‘&&c<=‘9‘)

       {

              now*=10;

              now+=c-‘0‘;

              c=getchar();

       }

       return f*now;

}

int main()

{

       freopen("jx.in","r",stdin);

       freopen("jx.out","w",stdout);

       n=read();

       for(int i=1;i<=n;i++)

         shuru[i]=read();

       for(int z=1;z<=3;z++)

       {    

              int su=-9999999;

              int wei;

              int ge;

      

              int op=0;

              int tot=0;

              for(int i=1;i<=n;i++)

              {

                     if(visited[i])

                     {

                            op=0;

                            tot=0;

                            continue;

                     }

                     if(op<0)

                     {

                            op=0;

                            tot=0;

                     }

                     op+=shuru[i];

                     tot++;

                     if(op>su)

                     {

                            su=op;

                            wei=i;

                            ge=tot;

                     }    

             }

             ans+=su;

             for(int i=wei-ge+1;i<=wei;i++)

                 visited[i]=1;

       }

       printf("%d",ans);

       fclose(stdin);

       fclose(stdout);

       return 0;

}

T3

密码锁 1000MS 512MB

Input: password.in

Output: password.out

【题目描述】

hzwer有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,...xk为开,其他开关为关时,密码锁才会打开。

他可以进行M种的操作,每种操作有一个size[i],表示,假如他选择了第i种的操作的话,他可以任意选择连续的size[i]个格子,把它们全部取反。(注意,由于黄金大神非常的神,所以操作次数可以无限>_<)

本来这是一个无关紧要的问题,但是,黄金大神不小心他的钱丢进去了,没有的钱他哪里能逃过被chenzeyu97 NTR的命运?>_<  于是,他为了虐爆czy,也为了去泡更多的妹子,决定打开这把锁。但是他那么神的人根本不屑这种”水题”。于是,他找到了你。

你的任务很简单,求出最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。

【输入格式】

第1行,三个正整数N,K,M,如题目所述。

第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。

第三行,M个正整数,表示size[i],size[]可能有重复元素。

【输出格式】

输出答案,无解输出-1。

方法::

以上是关于欢乐赛解题报告的主要内容,如果未能解决你的问题,请参考以下文章

NOI 2015 滞后赛解题报告

上岸算法 | LeetCode Weekly Contest 第 256 场周赛解题报告

SSL新年欢乐赛暨BPM退役赛

2017.5.26暴力赛解题报告

2016 ACM/ICPC亚洲区大连站-重现赛 解题报告

2020.5.10 个人rating赛 解题+补题报告