程序设计 week14 必做题

本文解析了三道算法竞赛题目,包括石头剪刀布博弈策略、十字叉填充优化及矩阵快速幂应用,涵盖博弈论、贪心算法、矩阵运算等核心概念。

A - Q老师与石头剪刀布(必做)

在这里插入图片描述

Input
2
3
1 1 1
RPS
3
3 0 0
RPS
Output
YES
PSR
NO

解题思路

实时的进行猜拳比赛,尽力让Q老师赢,如果Q老师所有能赢的局都赢了,
就比较是否超过了n/2次
如果不超过就输出No
如果超过了,就把那些输的局,用剩下能出的石头剪刀布给填满
输出结果

代码实现

#include<iostream>
#include<cstring>
using namespace std;
int t,n;
int a,b,c;
char s[305];
bool f[305];
char v[305];

int main()
{
	cin>>t;
	while(t--)
	{
		memset(s,0,sizeof(s));
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		cin>>n;
		cin>>a>>b>>c;
		
		int win_times;  //需要赢的次数
		if(n%2==0)
		win_times = n/2;
		else
		win_times = n/2 + 1;
		
		for(int i=0;i<n;i++)
		cin>>s[i];
		
		int win=0; int flag=0;
		for(int i=0;i<n;i++)
		{
			if(s[i]=='R' && b!=0)
			{
				win++;b--;f[i]=1;v[i]='P';
			}
			else if(s[i]=='P' && c!=0)
			{
				win++;c--;f[i]=1;v[i]='S';
			}
			else if(s[i]=='S' && a!=0)
			{
				win++;a--;f[i]=1;v[i]='R';
			}
			if(win>=win_times)
			{
				flag=1; break;
			}
		}
		if(flag == 0)  {
			cout<<"NO"<<endl; continue;
		}
		else {
			cout<<"YES"<<endl;
			for(int i=0;i<n;i++)
			{
				if(f[i]) cout<<v[i];
				else
				{
					if(a>0) { cout<<"R";a--;
					}
					else if(b>0){
						cout<<"P"; b--;
					}
					else if(c>0){
						cout<<"S"; c--;
					}
				}	
			}
			cout<<endl;
			continue;
		}
	}
	return 0;
}

B - Q老师与十字叉(必做)

在这里插入图片描述

Input
9
5 5
..*..
..*..
*****
..*..
..*..
3 4
****
.*..
.*..
4 3
***
*..
*..
*..
5 5
*****
*.*.*
*****
..*.*
..***
1 4
****
5 5
.....
..*..
.***.
..*..
.....
5 3
...
.*.
.*.
***
.*.
3 3
.*.
*.*
.*.
4 4
*.**
....
*.**
*.**
Output
0
0
0
0
0
4
1
1
2

思路

暴力做法
直接遍历,把每行每列的黑格子数给记下来
再遍历一次。把每个格子当做十字架的中心,然后
计算需要填多少黑格子
然后求出最小的,或者0

代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 5e4+5;
const int inf=1e9;
int q,n,m;
int row[N];  //一行有多少黑 
int col[N]; //一列有多少黑 

int main()
{
//	ios::sync_with_stdio(0);
//	cin>>q;
	scanf("%d",&q);
	while(q--)
	{
	//	cin>>n>>m;
		scanf("%d%d",&n,&m);
		char**c = new char*[n];
		for(int i=0;i<n;i++)
		{
			c[i]=new char[m];
		}
		
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				cin>>c[i][j];
			//	scanf("%c",&c[i][j]);
			}
		}
		
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(c[i][j]=='*') {
					row[i]++;
					col[j]++;
				}
			}
		}
		
		int min1=inf;
		bool flag=0;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				if(row[i]==m&&col[j]==n) {
		//			cout<<0<<endl;
					printf("0\n");
					flag = 1;break;
				}
				if(c[i][j]=='*') {
					min1 = min (min1,m-row[i]+n-col[j]);
				}
				else if(c[i][j]=='.')
				{
					min1 = min (min1,m-row[i]+n-col[j]-1);
				}
			}
			if(flag) break;
		}
		if(!flag)
	//	cout<<min1<<endl;
		printf("%d\n",min1);
		memset(row,0,sizeof row);
		memset(col,0,sizeof col);
	}
	return 0;
}

C - Q老师的考验(必做)

在这里插入图片描述

Sample Input
10 9999
1 1 1 1 1 1 1 1 1 1
20 500
1 0 1 0 1 0 1 0 1 0
Sample Output
45
104

解题思路

矩阵快速幂 + 线性递推

在这里插入图片描述

我们设 F(x) = M* F(x-1)
要想得到f(x),就必须得到F(x)
例如 F(13) = M^4 * F(9)
其中F(9)的值我们已知
就转换成了矩阵快速幂求 M^4

代码实现

#include<iostream>
#include<cstring>

using namespace std;
int k,m;
bool a[14];
const int N=10;

//矩阵定义
struct Matrix{
	int x[N][N];
	Matrix operator*(const Matrix& t) const{
		Matrix ret;
		for(int i=0;i<N;i++)
		{
			for(int j=0;j<N;j++)
			{
				ret.x[i][j]=0;
				for(int k=0;k<N;k++)
				{
					ret.x[i][j] +=x[i][k] * t.x[k][j] % m;
					ret.x[i][j] %=m;
				}
			}
		}
		return ret;
	}
	Matrix() { memset(x,0,sizeof x);
	}
	Matrix(const Matrix& t){ memcpy(x,t.x,sizeof x);
	}
};

//矩阵快速幂
Matrix quilck_pow(Matrix a,int x)
{
	Matrix ret;
	int n=0;
	while(n<N)//单位矩阵
	{
		ret.x[n][n] = 1;
		n++;
	}
	
	while(x){
		if(x&1) ret = ret * a;
		a=a*a;
		x>>=1;
	}
	return ret;
}

//求f(x)
int fun(int x)
{
	if(x<10) return x;
	
	else
	{
		Matrix M; //初始化矩阵 M
		for(int i=0;i<N;i++)
		M.x[0][i]=a[i];
		for(int i=1;i<N;i++)
		M.x[i][i-1] = 1;
		int pow=x-N+1;
		Matrix res;
		res=quilck_pow(M,pow);
		
		int sum=0;
		for(int i=0,j=9;i<N;j--,i++)
		{
			sum += (res.x[0][i] * j);
		}
		return sum;
	}
}

int main()
{
	while(cin>>k>>m)
	{
		memset(a,0,sizeof a);
		for(int i=0;i<N;i++)
		cin>>a[i];
		
		int res=fun(k);
		
		cout<<res%m<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值