河海大学第二十一届现场编程大赛-提高组 题解

河海大学第二十一届现场编程大赛-提高组 题解

如果觉得还有需要,你仍然可以连接我们的校园热点HHUC并登录10.11.12.75,在题库中能看到本次比赛的赛题,并可进行提交。

题目A w

题目大意

  判断所有消息的最后一个字母是否为w。
  请注意:有的消息可能没有字母,请不要把用户名最后的w作为判断消息最后是否为w的依据。

大致思路

  读入每行进行判断即可。

参考代码

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>

using namespace std;

int main()
{
	string s;
	char Rec;
	while (getline(cin, s))
	{
		int Pos = 0;
		while (s[Pos] != ':' && Pos < s.length())Pos++;
		Rec = 0;
		for (int i = s.length() - 1; i > Pos; --i)
		{
			if (s[i] >= 'A' && s[i] <= 'Z' || s[i] >= 'a' && s[i] <= 'z')
			{
				if (s[i] != 'w')
				{
					printf("No\n");
					return 0;
				}
				else break;
			}
		}
	}
	printf("Yes\n");
	return 0;
}

题目B 一道难题

题目大意

  现在给出一个正整数n,请找出最小的整数k使得集合{1, 2, 3, … ,n}中的取出任意k个数所组成子集T必然存在两个整数u,v∈T满足u是v的因子。

大致思路

  观察数据范围,基本确定解题思路为找规律。
  即可知选取超过一半的数字必然可使得有两个数字呈两倍关系。

参考代码

#include <cstdio>
#include <cstdlib>

using namespace std;

int T, n;

int main()
{
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &n);
		printf("%d ", (n + 1) / 2 + 1);
	}
	return 0;
}


题目C 数字迷宫

题目大意

  寻找所有区域中长度大于4、不能被拓展、相邻格子差值递增为1的路径。

大致思路

  首先排除搜索。题目中n、m数据量过大。观察题意,发现可以得到每个格子对先前的无后效性地推公式,即考虑使用动态规划。
  Dp[n][m][k]表示在第n行第m列中的那个数作为找到路径的第k个格子存在的不同路径(k≥4时可以视作最大值k=4,因为所有计算出的值无论是大于4的任何值都符合题意了)。
  依据地图中原有的值的大小进行排序,先进行小的值Dp的计算。
  那么动态转移方程Dp[n][m][k]的值必然从其四周4个方格,并需要符合差值为1。取得Dp[n’][m’][k-1]。Dp[n][m][4]亦可从Dp[n’][m’][4]转移得到。
  如果这个格子边上不存在比较其大于1的格子,则路径结束,对答案值进行统计。
  请注意对答案取模。

参考代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;

const int Modd = 1000000007;

int n, m;
int ans;
int Map[1010][1010];
struct node
{
	int num, x, y;
}a[1000010];
int dp[1010][1010][5];

bool cmp(node x, node y)
{
	return x.num < y.num;
}

const int Go[4][2] = { {0,1},{1,0},{-1,0},{0,-1} };

int main()
{
	memset(dp, 0, sizeof(dp));
	memset(Map, 0x7f, sizeof(Map));
	ans = 0;
	scanf("%d%d",&n,&m);
	int num = 0;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
		{
			scanf("%d", &Map[i][j]);
			a[++num].x = i;
			a[num].y = j;
			a[num].num = Map[i][j];
		}
	sort(a + 1, a + 1 + num, cmp);

	bool flag1, flag2;
	for (int i = 1; i <= num; ++i)
	{
		flag1 = true;//标记当前格子是否没有后继格子可走
		flag2 = true;//标记当前格子是否没有前置格子到达
		for (int j = 0; j < 4; ++j)
		{
			if (Map[a[i].x][a[i].y] + 1 == Map[a[i].x + Go[j][0]][a[i].y + Go[j][1]])flag1 = false;
			if (Map[a[i].x][a[i].y] - 1 == Map[a[i].x + Go[j][0]][a[i].y + Go[j][1]])
			{
				flag2 = false;
				for (int k = 2; k <= 4; ++k)
					dp[a[i].x][a[i].y][k] = (dp[a[i].x][a[i].y][k] + dp[a[i].x + Go[j][0]][a[i].y + Go[j][1]][k - 1]) % Modd;
				dp[a[i].x][a[i].y][4] = (dp[a[i].x][a[i].y][4] + dp[a[i].x + Go[j][0]][a[i].y + Go[j][1]][4]) % Modd;
			}
		}
		if (flag1)ans = (ans + dp[a[i].x][a[i].y][4]) % Modd;
		if (flag2)dp[a[i].x][a[i].y][1] = 1;
	}

	printf("%d", ans);
	return 0;
}

题目D 下围棋

题目大意

  依据题目要求进行一系列的操作。

大致思路

  依据题意进行模拟。该题为代码量题。可以适当采用并查集对围棋是否连块进行判断。

参考代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <algorithm>

using namespace std;

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

int n,m;
char S[1010];
int Map[1010][1010];

bool used[1010][1010];

queue<int> Q;

struct Point
{
	int x,y;
	bool operator <(const Point yy)const
	{
		if(x==yy.x)return y<yy.y;
		return x<yy.x;
	}
	bool operator ==(const Point yy)const
	{
		return (x==yy.x && y==yy.y);
	}
};
struct node
{
	int Fx,Fy;//Father
	int G;
	int Col;
	set<Point> s;
}IF[1010][1010];
int xx,yy;
int Tot=0; Point jl[10];

inline int Change(char ch){if(ch=='.')return 0;if(ch=='b')return 1;if(ch=='w')return 2;return 3;}
inline char Change(int num){if(num==0)return '.';if(num==1)return 'b';if(num==2)return 'w';return ' ';}
inline void AddGas(int x,int y,int gx,int gy)
{
	Point tmp;
	tmp.x=gx; tmp.y=gy;
	if(IF[x][y].s.count(tmp))return;
	IF[x][y].s.insert(tmp);
	++IF[x][y].G;
}
inline bool In(int x,int y)
{
	if(x>n || x<1)return false;
	if(y>n || y<1)return false;
	return true;
}
inline void Search(int xx,int yy)
{
	used[xx][yy]=true;
	IF[xx][yy].Fx=xx; IF[xx][yy].Fy=yy; IF[xx][yy].Col=Map[xx][yy]; IF[xx][yy].G=0;
	if(Map[xx][yy]==0)return;
	Q.push(xx); Q.push(yy);
	int x,y;
	int tx,ty;
	while(!Q.empty())
	{
		x=Q.front(); Q.pop(); y=Q.front(); Q.pop();
		for(int i=0;i<4;++i)
		{
			tx=x+Go[i][0]; ty=y+Go[i][1];
			if(Map[tx][ty]==Map[x][y] && !used[tx][ty])
			{
				Q.push(tx);	Q.push(ty);
				used[tx][ty]=true;IF[tx][ty].Fx=xx;IF[tx][ty].Fy=yy;IF[tx][ty].Col=Map[xx][yy];
			}
			if(Map[tx][ty]==0)AddGas(xx,yy,tx,ty);
		}
	}
}

inline Point GetFa(Point x)
{
	//if((Point){IF[x.x][x.y].Fx,IF[x.x][x.y].Fy}==x)return x;
	if(IF[x.x][x.y].Fx==x.x && IF[x.x][x.y].Fy==x.y)return x;
	Point HH; HH.x=IF[x.x][x.y].Fx; HH.y=IF[x.x][x.y].Fy;
	HH=GetFa(HH);
	IF[x.x][x.y].Fx=HH.x; IF[x.x][x.y].Fy=HH.y;
	return HH;
}

inline int Calc_Gas(int xx,int yy,int C)
{
	int tot=0; Point Ss;
	for(int i=0;i<4;++i)
		if(In(xx+Go[i][0],yy+Go[i][1]))
			tot+=(IF[xx+Go[i][0]][yy+Go[i][1]].Col==0);
	Tot=0;
	for(int i=0;i<4;++i)
		if(IF[xx+Go[i][0]][yy+Go[i][1]].Col==C)
		{
			Ss.x=xx+Go[i][0]; Ss.y=yy+Go[i][1];
			jl[++Tot]=GetFa(Ss);
			tot+=IF[jl[Tot].x][jl[Tot].y].G-1;
		}
	return tot;
}

inline bool cmp(Point x,Point y)
{
	return IF[x.x][x.y].G>IF[y.x][y.y].G;
}

inline void Link(int xx,int yy,int C)
{
	Point Ss;
	sort(jl+1,jl+1+Tot,cmp);
	int x,y;
	if(Tot)x=IF[jl[1].x][jl[1].y].Fx,y=IF[jl[1].x][jl[1].y].Fy;
	else 
	{
		x=xx,y=yy;
		IF[xx][yy].G=0; IF[xx][yy].s.clear();
	}
	IF[xx][yy].Fx=x; IF[xx][yy].Fy=y; IF[xx][yy].Col=C;
	for(int i=2;i<=Tot;++i)
	{
		if(x==jl[i].x && y==jl[i].y)continue;
		IF[jl[i].x][jl[i].y].Fx=x;
		IF[jl[i].x][jl[i].y].Fy=y;
		while(!IF[jl[i].x][jl[i].y].s.empty())
		{
			Ss=*IF[jl[i].x][jl[i].y].s.begin();
			IF[jl[i].x][jl[i].y].s.erase(IF[jl[i].x][jl[i].y].s.begin());
			if(IF[x][y].s.count(Ss)==0)
			{
				IF[x][y].s.insert(Ss);
				++IF[x][y].G;
			}
		}
	}
	for(int i=0;i<4;++i)
		if(In(xx+Go[i][0],yy+Go[i][1]))
			if(IF[xx+Go[i][0]][yy+Go[i][1]].Col==0)
			{
				Ss.x=xx+Go[i][0];
				Ss.y=yy+Go[i][1];
				if(IF[x][y].s.count(Ss)==0)
				{
					IF[x][y].s.insert(Ss);
					++IF[x][y].G;
				}
			}
	if(Tot)
	{
		--IF[x][y].G;
		Ss.x=xx; Ss.y=yy;
		IF[x][y].s.erase(Ss);
	}
}

inline bool Find(int xx,int yy)
{
	for(int i=0;i<4;++i)if(IF[xx+Go[i][0]][yy+Go[i][1]].Col==IF[xx][yy].Col)return true;
	return false;
}

inline void AddNearbyGas(int xx,int yy)
{
	Point Ss,emp;
	emp.x=xx; emp.y=yy;
	for(int i=0;i<4;++i)
	{
		Ss.x=xx+Go[i][0]; Ss.y=yy+Go[i][1];
		Ss=GetFa(Ss);
		if(IF[Ss.x][Ss.y].s.count(emp)==0)
		{
			IF[Ss.x][Ss.y].s.insert(emp);
			++IF[Ss.x][Ss.y].G;
		}
	}
}

inline int Del(int xx,int yy,int C)
{
	Point X,Ss; int ret=0;
	X.x=xx; X.y=yy;
	for(int i=0;i<4;++i)
	{
		if(IF[xx+Go[i][0]][yy+Go[i][1]].Col!=0 && IF[xx+Go[i][0]][yy+Go[i][1]].Col!=C)
		{
			Ss.x=xx+Go[i][0]; Ss.y=yy+Go[i][1];
			Ss=GetFa(Ss);
			if(IF[Ss.x][Ss.y].s.count(X))
			{
				--IF[Ss.x][Ss.y].G;
				IF[Ss.x][Ss.y].s.erase(X);
				if(IF[Ss.x][Ss.y].G==0)
				{
					if(Find(Ss.x,Ss.y))ret+=2;
					else 
					{
						ret+=1;
						AddNearbyGas(Ss.x,Ss.y);
					}
					IF[Ss.x][Ss.y].Col=0;
				}
			}
		}
	}
	return ret;
}

inline void Print()
{
	Point Ss;
	puts("");
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		{
			Ss.x=i; Ss.y=j;
			Ss=GetFa(Ss);
			printf("%c",Change(IF[Ss.x][Ss.y].Col));
		}
		puts("");
	}
}

int main()
{
	memset(Map,-1,sizeof(Map));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	{
		scanf("%s",S+1);
		for(int j=1;j<=n;++j)Map[i][j]=Change(S[j]);
	}
	memset(used,false,sizeof(used));
	while(!Q.empty())Q.pop();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(!used[i][j])
				Search(i,j);
	bool B=false;
	while(m--)
	{
		B^=true;
		scanf("%d%d",&xx,&yy);
		if(IF[xx][yy].Col!=0){printf("N");continue;}
		int G=Calc_Gas(xx,yy,2-B);
		if(G!=0)
		{
			printf("Y");
			Link(xx,yy,2-B);
			if(Del(xx,yy,2-B)>1)
			{
				Print();
				printf("%sWin\n",B?"Black":"White");
				return 0;
			}
			//Print();
			continue;
		}
		if(int XX=Del(xx,yy,2-B))
		{
			printf("Y");
			Link(xx,yy,2-B);
			if(XX>1)
			{
				Print();
				printf("%sWin\n",B?"Black":"White");
				return 0;
			}
			//Print();
			continue;
		}
		printf("N");
	}
	
	Print();
	return 0;
}

题目E 玩游戏

题目大意

  通过技能、移动进行刷野怪。计算t时间内的最大值。

大致思路

  又是一道动态规划题。
  动态方程4个状态分别表示,在哪个点,在第几秒,还有几次技能以及技能的CD。具体操作如代码所示。

参考代码

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

using namespace std;

int n, m, t, k, b;
int a[55][55], e[55][55];
int f[65][55][6][6];

inline void checkMax(int &x, int y)
{
	if (y > x) x = y;
}

inline void work()
{
	memset(e, 0, sizeof e);
	memset(a, 0, sizeof a);
	scanf("%d %d %d %d %d", &n, &m, &t, &k, &b);
	
	int x, y, z;
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d %d %d", &x, &y, &z);
		e[x][y] = e[y][x] = z;
	}
	for (int i = 1; i <= k; ++i)
	{
		scanf("%d %d %d", &x, &y, &z);
		a[x][y] += z;
	}
	memset(f, 0xbf, sizeof f);
	for (int i = 1; i <= n; ++i)
		f[1][i][0][b] = 0;
	int cur, ans = 0;
	for (int i = 1; i <= t; ++i)
		for (int j = 1; j <= n; ++j)	
			for (int c = 0; c <= 5; ++c)
				for (int d = 0; d <= b; ++d)
					if (f[i][j][c][d] >= 0)
					{
						if (c == 0 && d > 0)
						{
							cur = f[i][j][c][d];
							for (int z = 1; z <= n; ++z)
								if (e[j][z] > 0)
									cur += a[i][z];
							checkMax(f[i][j][5][d - 1], cur); 
						}
						cur = f[i][j][c][d] + a[i][j];
						checkMax(ans, cur);
						checkMax(f[i + 1][j][max(c - 1, 0)][d], cur);
						for (int z = 1; z <= n; ++z)
							if (e[j][z] > 0)
								checkMax(f[i + e[j][z]][z][max(c - e[j][z], 0)][d], cur);
					}
	printf("%d\n", ans);
}

int main()
{
	work();
	return 0;
}

题目F 郊游

题目大意

  通过一系列的计算还原值。

大致思路

  数学题。使用快速幂计算即可。即 n n − n + 1 n^n-n+1 nnn+1,不要忘记求余。

参考代码

#include <cstdio>  
#include <iostream>
#include <cstring> 
#include <cstdlib>

using namespace std;
 
long long pow_mod(long long a,long long n,long long m)
{
	if (n==0) return 1;
	if (n==1) return a%m;
	long long x=pow_mod(a,n/2,m);
	long long ans=(long long)x*x%m;
	if (n%2) ans=ans*a%m;
	return (long long)ans;
}

long long n,k;  
long long w;

int main() 
{
    cin>>n>>k;
    w=pow_mod(n,n,k)-n%k+1;
    for (;w<0;w+=k);
    cout<<w%k<<endl;
	return 0; 
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值