歡樂賽解題報告
~~一場不歡樂的歡樂賽
時間分配::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。
方法::
歡樂賽解題報告