第八届湘潭大学程序设计比赛(题解)


柳爷镇楼:



 ? Problem AA Love Letter 
 ? Problem BBob's Problem 
 ? Problem CCipher Lock 
 ? Problem DDouble Maze 
 ? Problem EEasy Wuxing 
 ? Problem FFlappy Bird 
 ? Problem GGame of Wuxing 
 ? Problem HHard Wuxing


A Love Letter

Accepted : 43 Submit : 102
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

  CodeMonkey终于下定决心用情书的方式向心爱的女神表白,当他历经几天几夜写完之后才知道女神有很多不喜欢的词,所以他不得不有把这些词删掉。例如:原文是:ILOVEYOU,女神不喜欢的词是‘LV’,‘O’那么最终情书要改成IEYU。现在已知女生不喜欢的词的集合S,CodeMonkey想知道刚写的情书会改成什么样?S={“HATE”,“SHIT”,“LV”,“O”,“FUCK”,“UGLY”,“MM”}

输入

  多样例输入,每个样例输入一行情书原文,原文只包含大写英文字母,原文长度不超过1000

输出

  对于每个样例,若是情书被删完则输出一行“LOSER”,否则输出情书的剩余内容

样例输入
ILOVEYOU
MM

样例输出
IEYU
LOSER


标准做法是用栈,不过随便就能水过去,柳爷抢到FB
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

string str;
const char dict[20][200]={"HATE","SHIT","LV","O","FUCK","UGLY","MM"};
const int leng[10]={4,4,2,1,4,4,2};

string zhenghe(string str)
{
    string ans;
    int n=str.size();
    for(int i=0;i<n;i++) if(str[i]!='@') ans+=str[i];
    return ans;
}

bool ck()
{
    bool flag=false;
    for(int i=0;i<7;i++)
    {
        int t=-1;
        t=str.find(dict[i]);
        if(~t)
        {
            flag=true;
            for(int j=t;j<t+leng[i];j++)
            {
                str[j]='@';
            }
        }
    }
    str=zhenghe(str);
    return flag;
}

int main()
{
    freopen("std.in","r",stdin);
    freopen("out.txt","w",stdout);
while(cin>>str)
{
    while(ck());
    if(str.size()) cout<<str<<endl;
    else cout<<"LOSER\n";
}
    return 0;
}


Bob's Problem

Accepted : 47 Submit : 307
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

Bob今天碰到一个问题,他想知道x3+y3 = c 是否存在正整数解?

输入

第一行是一个整数K(K≤20000),表示样例的个数。 以后每行一个整数c(2≤c≤109)

输出

每行输出一个样例的结果,如果存在,输出“Yes”,否则输出“No”。(引号不用输出)

样例输入
2
28
27

样例输出
Yes
No



1000×1000的预处理,处理出所有可能的立方和,二分查找即可,
当然也有复杂度数学方法:拆成(x+y)*(x^2-xy+y^2)解方程。。。。最后还要枚举 ,柳叶又抢个FB

#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#include <algorithm>

using namespace std;

int nb[3000],tot=0;

int main()
{
    freopen("std.in","r",stdin);
    freopen("out.txt","w",stdout);
    set<int> st; st.clear();
    for(int i=1;i<1010;i++)
    {
        nb[tot++]=i*i*i;
    }
    for(int i=0;i<tot;i++)
    {
        for(int j=i;j<tot;j++)
        {
            st.insert(nb[i]+nb[j]);
        }
    }
    int a,T_T;
while(scanf("%d",&T_T)!=EOF)
{
while(T_T--)
{
    scanf("%d",&a);
    int flag=st.count(a);
    if(flag) puts("Yes");
    else puts("No");
}
}
    return 0;
}

Cipher Lock

Accepted : 23 Submit : 76
Time Limit : 2500 MS Memory Limit : 65536 KB 

题目描述

守护着神秘宝藏One Piece的是一把非常神秘的密码锁,这个密码锁有n排滚轮,每个滚轮有m个格子,刻着0,1两种数字。作为一把神秘的密码锁,开锁的方式却非常的简单,只要向左或向右转动滚轮使某一列的数字全是1就可以了。(向左滚动:所有的数字向左移动一位,最左边的数字移动到最右边,如001100左滚动一次变为011000,向右滚动与向左滚动操作相同,只是方向相反),作为即将成为海贼王的你,一定会选择最帅气的开锁方式———既用最少的次数来打开守护着神秘宝藏One Piece的密码锁。那么,请问最帅气的开锁次数需要转动密码锁几次呢?

输入

有多组数据输入,每个数据第一行为两个整数n,m表示有n排密码锁,每个密码锁有m个格子,其中(1≤n≤100,1≤m≤104)。接下来的有n行输入,表示每排密码锁的初始状态。

输出

对每组数据输出两行,第一行输出“Case # :”表示当前是几号样例(从1开始编号),第二行,如果可以开锁就输出一个整数表示最少需要移动几次,否则输出“Give Me A BOOM please”。(均不用输出“”号)

样例输入
2 3
111
000
3 6
101010
000100
100000

样例输出
Case #1:
Give Me A BOOM please
Case #2:
3

提示

对第一个样例,不可能开锁。第二个样例,可以第2行向左滚动一次,第3行向右滚动2次,最少3次就可以解锁。

作者

码代码的猿猿


预处理出所有位置到最近1的距离,然后枚举每一列
标程几个月前写的不算很精简,而且数据没有特意的构造,暴力一些的方法也能水过去。。。

标程:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m,g[110][33000],dis[110][33000];
const int INF=0x3f3f3f3f;

int main()
{
    ///freopen("input.txt","r",stdin);
    ///freopen("output.txt","w",stdout);
    int cas=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
	memset(dis,63,sizeof(dis));
    getchar();
	int B1=m,B2=2*m,B3=3*m;
	for(int i=0;i<n;i++)
	{
	    bool flag=false;
		for(int j=0;j<m;j++)
		{
		    char c;
		    scanf("%c",&c);
            g[i][j]=(c=='1')?1:0;
			g[i][j+B1]=g[i][j+B2]=g[i][j];
			if(g[i][j]==1) dis[i][j+B1]=0;
		}
		getchar();
	}
    ///left_distance
    for(int i=0;i<n;i++)
    {
        bool flag=false;
        int dist=0;
        for(int k=B1-1;k>=0;k--)
        {
            dist++;
            if(g[i][k]==1) {flag=true; break;}
        }
        if(flag==false) continue;
        dis[i][B1]=min(dis[i][B1],dist);
        for(int j=B1+1;j<B2;j++)
        {
            if(dis[i][j]==0) continue;
            else dis[i][j]=dis[i][j-1]+1;
        }
    }
    ///right_distance
	for(int i=0;i<n;i++)
	{
	    bool flag=false;
	    int dist=0;
	    for(int k=B2;k<B3;k++)
        {
            dist++;
            if(g[i][k]==1) {flag=true; break;}
        }
        if(flag==false) continue;
        dis[i][B2-1]=min(dis[i][B2-1],dist);
        for(int j=B2-2;j>=B1;j--)
        {
            if(dis[i][j]==0) continue;
            else dis[i][j]=min(dis[i][j],dis[i][j+1]+1);
        }
	}
	int ans=INF;
	for(int i=B1;i<B2;i++)
    {
        int temp=0;
        bool flag=true;
        for(int j=0;j<n;j++)
        {
            if(dis[j][i]==INF)
            {
                flag=false; break;
            }
            temp+=dis[j][i];
        }
        if(flag) ans=min(ans,temp);
        else { ans=INF; break; }
    }
    printf("Case #%d:\n",cas++);
    if(ans>=INF) puts("Give Me A BOOM please");
    else printf("%d\n",ans);
}
    return 0;
}

Double Maze

Accepted : 32 Submit : 57
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

一个迷宫里,有两个点,你的任务是给出尽可能短的一系列的命令,让这两个点一起执行这些命令能走到一起。如果某个点按某个命令走会走出迷宫或走到障碍上,则忽略这条命令。

输入

输入不超过1000个样例,每个样例第一行有两个整数n,m(2≤n,m≤11),之后n行每行m个字符,'.'表示能走的地方,'#'表示障碍,‘*'表示其中一个点。每个样例之间有一个空行。

输出

每个样例输出一行,包含'U','D','L','R'。'U'表示向上走的命令,'D'表示向下,'L'表示向左,'R'表示向右。要是有多个答案,输出字典序最小的序列。如果无法达到目标,输出“Sorry”(引号不要输出)。

样例输入
4 11
*.##..#..#*
...#..#.#..
.##.#.#.##.
##..###....

4 4
.*..
.###
...*
....

10 10
*.........
#########.
..........
.#########
..........
#########.
..........
.#########
.........*
##########

样例输出
Sorry
LLLUU
LLLLLLLLLUURRRRRRRRRUULLLLLLLLLUURRRRRRRRRDD


有两个点的普通bfs。。。。但比赛的时候只有柳爷一个人出。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <set>

using namespace std;

struct PT
{
    int x1,y1,x2,y2;
    string gogogo;
};

const int dir_x[4]={1,0,0,-1};
const int dir_y[4]={0,-1,1,0};
const char dir[4]={'D','L','R','U'};

char mp[20][20];
int n,m;

int hash(int a,int b,int c,int d)
{
    int ret=a;
    ret=ret*100+b;
    ret=ret*100+c;
    ret=ret*100+d;
    return ret;
}

void ck(int& x1,int& y1,int& x2,int& y2,int d)
{
    if(x1<0||x1>=n||y1<0||y1>=m||mp[x1][y1]=='#')
    {
        x1=x1-dir_x[d];y1=y1-dir_y[d];
    }
    if(x2<0||x2>=n||y2<0||y2>=m||mp[x2][y2]=='#')
    {
        x2=x2-dir_x[d];y2=y2-dir_y[d];
    }
}

int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
    int a=0,b=0,c=0,d=0;
    for(int i=0;i<n;i++) scanf("%s",mp[i]);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(mp[i][j]=='*')
            {
                if(a==0&&b==0)
                {
                    a=i;b=j;
                }
                else
                {
                    c=i;d=j;
                }
            }
        }
    }
    PT ac=(PT){a,b,c,d,"@"};

    queue<PT> q;
    q.push(ac);
    set<int> st;
    st.insert(hash(a,b,c,d));
    bool flag=false;
    string ans;
    while(!q.empty())
    {
        PT u=q.front(),v; q.pop();
        if(flag&&u.gogogo.size()>ans.size()) break;
        if(u.x1==u.x2&&u.y1==u.y2)
        {
            if(ans.size()==0) ans=u.gogogo;
            else if(ans>u.gogogo) ans=u.gogogo;
            flag=true;
        }
        for(int i=0;i<4;i++)
        {
            int X1=u.x1+dir_x[i],X2=u.x2+dir_x[i];
            int Y1=u.y1+dir_y[i],Y2=u.y2+dir_y[i];
            ck(X1,Y1,X2,Y2,i);

            string R=u.gogogo+dir[i];
            int h=hash(X1,Y1,X2,Y2);
            if(!st.count(h))
            {
                st.insert(h);
                v=(PT){X1,Y1,X2,Y2,R};
                q.push(v);
            }
        }
    }
    if(!flag) cout<<"Sorry\n";
    else
    {
        int n=ans.size();
        for(int i=1;i<n;i++) cout<<ans[i];
        cout<<endl;
    }
}
    return 0;
}


Easy Wuxing

Accepted : 21 Submit : 89
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

“五行”是中国传统哲学思想,它认为认为大自然的现象由“木、火、土、金、水”这五种气的变化所总括, 不但影响到人的命运,同时也使宇宙万物循环不已。 五行具有相生相克的性质,规律如下:

  • 五行相克:金克木,木克土,土克水,水克火,火克金。
  • 五行相生:金生水,水生木,木生火,火生土,土生金。
  • 五行任一行与其他五行的关系为:同我、生我、我生、克我、我克。


给你一个1*n的格子,将五行填上去,每格填一个,要求相邻格以及首尾格不能是同我和相克的关系, 请问一共有多少种不同的方案?

 

输入

多组样例,每组一个整数n(0≤n≤106),如果n为0,表示输入结束,这个样例不需要处理。

输出

每行输出一个样例的结果,因为数值可能非常大,请将结果对109+7取模。

样例输入
1
2
0


样例输出
5
10





Hard Wuxing

Accepted : 11 Submit : 153
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

“五行”是中国传统哲学思想,它认为认为大自然的现象由“木、火、土、金、水”这五种气的变化所总括, 不但影响到人的命运,同时也使宇宙万物循环不已。 五行具有相生相克的性质,规律如下:

  • 五行相克:金克木,木克土,土克水,水克火,火克金。
  • 五行相生:金生水,水生木,木生火,火生土,土生金。
  • 五行任一行与其他五行的关系为:同我、生我、我生、克我、我克。


给你一个1*n的格子,将五行填上去,每格填一个,要求相邻格以及首尾格不能是同我和相克的关系, 请问一共有多少种不同的方案?

 

输入

多组样例,每组一个整数n(0≤n≤1018),如果n为0,表示输入结束,这个样例不需要处理。

输出

每行输出一个样例的结果,因为数值可能非常大,请将结果对109+7取模。

样例输入
1
2
0


样例输出
5
10

两题是一样的,只是数据范围不同。。。。
找出递推关系式然后用矩阵快速幂。。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const long long int MOD=1e9+7;

struct MARTRIX
{
    long long int m[5][5];
}E,A;

void init()
{
    memset(E.m,0,sizeof(E.m));
    memset(A.m,0,sizeof(A.m));
    E.m[0][0]=E.m[1][1]=E.m[2][2]=1;
    A.m[0][2]=A.m[1][1]=A.m[1][2]=A.m[2][1]=1;
    A.m[2][0]=2;
}

MARTRIX muil(MARTRIX a,MARTRIX b)
{
    MARTRIX ANS;
    memset(ANS.m,0,sizeof(ANS.m));
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            ANS.m[i][j]=0;
            for(int k=0;k<3;k++)
            {
                ANS.m[i][j]=(ANS.m[i][j]+a.m[i][k]*b.m[k][j]%MOD)%MOD;
            }
        }
    }
    return ANS;
}

MARTRIX POW(long long int n)
{
    init();
    while(n)
    {
        if(n&1LL) E=muil(E,A);
        A=muil(A,A);
        n>>=1;
    }
    return E;
}

void solve(long long int n)
{
    MARTRIX M=POW(n);

    printf("%I64d\n",(M.m[0][0]*5)%MOD);
}

int main()
{

    long long int n;
while(scanf("%I64d",&n)!=EOF)
{
    if(n<=3)
    {
        if(n==1) puts("5");
        else if(n==2) puts("10");
        else if(n==3) puts("0");
        continue;
    }
    solve(n);
}
    return 0;
}



Flappy Bird

Accepted : 6 Submit : 28
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

Henry最近迷上Flappy Bird这个小游戏,这个需要不断控制点击屏幕的频率来调节小鸟的飞行高度和降落速度,让小鸟顺利地通过画面右端的通道,如果不小心撞到了通道的话,游戏便宣告结束。 我们来简化一下这个游戏,如图所示,画面的高度为17,通道的宽度为2,上下通道之间所留的空间长度始终为3,每相邻的两个通道之间相距4个单位,小鸟占据单位1的面积,且始终向画面右端移动,每秒移动1列。我们可以在这一秒内控制小鸟上升、下降或者维持在原有的高度不变。每当小鸟通过了一个通道(即完全穿越过这个通道),便获得1分,当小鸟撞击到了通道,游戏结束。 在通过第一个通道之前,Henry可以凭借他犀利的操作使小鸟处于任意的高度。 现在Henry已经得到了通道的排布情况,他希望聪明的你能告诉他最多能获得的分数。 

输入

第一行为1个整数T,表示样例的个数。 每个样例的第一行是一个整数N(1≤N≤500), 接下来有N行,每行两个整数x,y,分别表示上通道的底部和下通道的顶部所在 的格子的位置,(8≥x>y≥-8, x-y-1=3)

输出

对于每个样例输出一行,表示小鸟所得的分数, 如果小鸟能通过所有的通道,则输出win

样例输入
2
2
2 -2
4 0
3
2 -2
-2 -6
8 4

样例输出
win
2


位运算,有两点要注意:1,一个间隔内小鸟可以移动5次(挨到管子时还能动一下)
2,在管子内还可以移动。。。不过出题的时候没考虑好,-8~8的范围内没有可以卡在是否管子内移动的情况。。。
有些没有考虑管子内移动的代码也AC了
柳叶的第N个FB

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

int flappy[1000],bird,n;

int main()
{
    freopen("std2.in","r",stdin);
    freopen("out2.txt","w",stdout);
    int T_T,l,r;
    scanf("%d",&T_T);
while(T_T--)
{
    scanf("%d",&n);
    memset(flappy,0,sizeof(flappy));
    bird=0;
    for(int i=0;i<n;i++)
    {
        scanf("%d%d",&r,&l);
        l+=9,r+=7;
        for(int j=l;j<=r;j++)
        {
            flappy[i]|=(1<<j);
        }
    }

    int ans=1;
    bird=flappy[0];
    for(int j=1;j<n;j++)
    {
        int B=0;
        for(int i=0;i<=5;i++)
        {
            B|=(bird>>i);
            B|=(bird<<i);
        }

        if(B&flappy[j])
        {
            ans++;
            bird=0;
            B=B&flappy[j];
            for(int i=0;i<=2;i++)
            {
                bird|=((B<<i)&flappy[j]);
                bird|=((B>>i)&flappy[j]);
            }
        }
        else break;
    }
    if(ans==n) puts("win");
    else printf("%d\n",ans);
}
    return 0;
}


Game of Wuxing

Accepted : 18 Submit : 35
Time Limit : 1000 MS Memory Limit : 65536 KB 

题目描述

“五行”是中国传统哲学思想,它认为大自然的现象由“木、火、土、金、水”这五种气的变化所总括, 不但影响到人的命运,同时也使宇宙万物循环不已。 五行具有相生相克的性质,规律如下:

  • 五行相克:金克木,木克土,土克水,水克火,火克金。
  • 五行相生:金生水,水生木,木生火,火生土,土生金。
  • 五行任一行与其他五行的关系为:同我、生我、我生、克我、我克。


传说古代有一种游戏,有一些骨牌,骨牌上刻有五行属性和点数(点数从1到9)。 游戏时,甲和乙各抽5张骨牌,然后每轮,两人各出一张牌,翻开以后比较:

  • 如果甲和乙构成同我关系,则两人各得自己牌的得分;
  • 如果甲和乙构成生我关系(即乙生甲),比如说甲出金,乙出土,那么两张牌的点数之和为甲的得分;
  • 如果甲和乙构成我克关系(即甲克乙),比如说甲出金,乙出木,那么两张牌的点数之差(绝对值)为甲的得分;

最后得分多者为胜。 现在给你甲和乙的出牌顺序,请计算一下游戏的结果。

 

输入

第一行是一个整数K,表示样例的个数。 以后每个样例占5行,为5次出的牌。每行按甲乙的顺序给出牌。 每张牌的类型,即金木水火土分别使用J、M、S、H、T5个大写英文表示。 点数使用数字1-9表示。 两牌之间有一个空格。

输出

每个样例输出一行,如果甲胜输出“Jia”,乙胜输出“Yi”,平局输出“Ping”。(不要输出引号)。

样例输入
3
J1 J1
J1 M1
J1 S1
J1 H1
J1 T1
J1 J1
J1 M2
J1 S3
J1 H4
J1 T6
J1 J1
J1 M2
J1 S3
J1 H4
J1 T4


样例输出
Ping
Jia
Yi



地道的水题,FB还是柳爷的

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

int getID(char x)
{
    if(x=='J') return 0;
    else if(x=='S') return 1;
    else if(x=='M') return 2;
    else if(x=='H') return 3;
    else if(x=='T') return 4;
}

int main()
{
    int T_T;
    scanf("%d",&T_T);
while(T_T--)
{
    int a,b,jia=0,yi=0;
    char c1,c2;
    char st1[10],st2[10];
    for(int i=0;i<5;i++)
    {
        scanf("%s%s",st1,st2);
        c1=st1[0],a=st1[1]-'0';
        c2=st2[0],b=st2[1]-'0';
        int id1=getID(c1),id2=getID(c2);
        int D=(id1-id2+5)%5;
        if(D==0)
        {
            jia+=a,yi+=b;
        }
        else if(D==1)
        {
            jia+=(a+b);
        }
        else if(D==4 )
        {
            yi+=(a+b);
        }
        else if(D==2)
        {
            yi+=abs(a-b);
        }
        else if(D==3)
        {
            jia+=abs(a-b);
        }
    }
    if(jia==yi) printf("Ping\n");
    else if(jia>yi) printf("Jia\n");
    else if(yi>jia) printf("Yi\n");
}
    return 0;
}


总的来说,这次题目非常的水。。。。

PS:柳爷比赛的节奏就是:啪啪啪 拿下B题的 FB,然后 啪啪啪 拿下A题的 FB ,再 啪啪啪 D题的FB ,又啪啪啪 G题的FB。。。。
最后啪啪啪,确认冠军到手后,潇洒的提前离场去补考线代去了。。。。。ORZ  第一次见到有人能得这么多气球。。。这么多的FB


























  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值