1. 程式人生 > >歡樂賽解題報告

歡樂賽解題報告

輸入 不同 eof ~~ ostream 同步 題目 由於 .cpp

~~一場不歡樂的歡樂賽

時間分配::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。

方法::

歡樂賽解題報告