2020第十一届B组国赛题解

B.扩散

在这里插入图片描述

解题思路

就是简单BFS,只是需要考虑负数的情况;因为最多到[-2020,2020],因此,全部起点进行[x+2500,y+2500]操作;
代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*
20312088
*/
struct node{
	int x,y;
	int step;
};
bool vis[10000][10000];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int main(){
	queue<node>q;
	node New;
	New.step=1;
	New.x=0+2500,New.y=0+2500; 
	q.push(New);
	New.x=2020+2500,New.y=11+2500; 
	q.push(New);
	New.x=11+2500,New.y=14+2500; 
	q.push(New);
	New.x=2000+2500,New.y=2000+2500; 
	q.push(New);
	int ans=0;
	while(!q.empty()){
		node temp=q.front();
		q.pop();
		vis[temp.x][temp.y]=1;
		ans++;
		for(int i=0;i<4;i++){
			int fx=temp.x+dx[i];
			int fy=temp.y+dy[i];
			if(!vis[fx][fy]&&temp.step<=2020){//涉及次数问题一定要理清楚+用可以手算的样例试试 
				vis[fx][fy]=1;//!!这个一定要加 
				New.step=temp.step+1;
				New.x=fx,New.y=fy;
				q.push(New);
			}
		}
	} 
	cout<<ans<<endl;
	return 0;
}

总结

但是在考试的没做出来,而且又尝试一遍,还是有问题~~;分析了下原因,一个是因为自己广搜不熟练,不知道vis[x][y]放在哪里;另一个就是对于步数的边界条件判断错误。

C.阶乘约数

在这里插入图片描述

解题思路

我们只需要知道一个公式就可以:

一个数n=p[1]^e1*p[2]^e2~~~
·这里的p[i]是它的质因子,ei是因子个数
则有sum(n)=(e1+1)*(e2+1)~~*(ei+1);
sum(n)表示n的约数总个数;

代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*
数论 
39001250856960000
*/
int prim[105];
int main(){
	for(int i=1;i<=100;i++){
		int k=i;
		for(int j=2;j*j<=i;j++){//必须是i,因为必须保证 j*j<=i,才能完全考虑 
			while(k%j==0){
				prim[j]++;
				k=k/j;
			}
		}
		if(k!=1)prim[k]++;
	} 
	long long ans=1;
	for(int i=2;i<=100;i++){
		if(prim[i]){//阿sir,都不会区分 ==0和!=0了?? 
			ans*=(prim[i]+1);
			cout<<ans<<" "<<prim[i]+1<<endl;
		}
			
	}
	cout<<ans<<endl;
	return 0;
}

总结

就是数论知识,但是不知道的话也可以现场推导;
在这里插入图片描述

D.本质上升序列

在这里插入图片描述

解题思路

考试的时候想到的是深搜,但是估计了下时间,到考试结束都跑不出来~;
广搜

1.根据题目的样例,不难观察出,长度为2的子串是在长度为1的子串基础上扩展来的~~
2.所以可以利用广搜的层次性,初始化<string,int>即子串和它的末尾下标;
3.然后广搜即可;

4.需要注意的是,初始话的时候对于重复字母的判断:
在这里插入图片描述

代码展示

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
using namespace std;
#define mk make_pair 
const int inf=0x3f3f3f3f;
typedef long long ll;
int n,m,ans;
char s[500]="tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
/*
3616159
3616159
广搜的层次性??
与深搜不同,深搜是一直得到一个子串,; 
*/ 
map<string,bool>vis;
int main()
{
	queue<pair<string,int> >q;//子串string的末端节点是pos 
	while(!q.empty())q.pop(); 
	int l=strlen(s);
	for(int i=0;i<l;i++){
		if(!vis[s[i]+""]){
			q.push(mk(s[i]+"",i));//mk是啥??
			vis[s[i]+""]=1; 
		}
	}
	int ans=0;
	while(!q.empty()){
		string str=q.front().first;
		int kt=q.front().second;
		q.pop();
		ans++;
		cout<<"A "<<str<<endl;
		for(int i=kt+1;i<l;i++){
			if(s[kt]<s[i]&&!vis[str+s[i]]){
				q.push(mk(str+s[i],i));
				vis[str+s[i]]=1;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
} 

总结

LIS、LCS等几个经典动规问题都要了解;

E.玩具蛇

在这里插入图片描述

解题思路

简单的深搜,考试的时候脑子短路,没想起来~
代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*

*/
int ans;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
bool vis[20][20];
void DFS(int x,int y,int k){//操,一定要用文字理一遍DFS的意思!~!!! 
//	cout<<x<<" "<<y<<" "<<k<<endl;
	if(k>=16){
		ans++;
		return;
	}
	for(int i=0;i<4;i++){
		int fx=x+dx[i];int fy=y+dy[i];
		if(fx>=1&&fx<=4&&fy>=1&&fy<=4){
			if(!vis[fx][fy]){
			vis[fx][fy]=1;
			DFS(fx,fy,k+1);//淦 
			vis[fx][fy]=0;
		    }
		}
		
	}
}
int main(){
	for(int i=1;i<=4;i++){
		for(int j=1;j<=4;j++){
			memset(vis,0,sizeof(vis));
			vis[i][j]=1;
			DFS(i,j,1);
			cout<<ans<<endl;
		}
	}
	return 0;
}

总结

深搜时,一定要注意对递归边界的判断;我的方法就是定义深搜函数时搞清楚这个深搜的作用。

F.皮亚诺曲线

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解题思路

代码展示


总结

G.游园安排

在这里插入图片描述

解题思路

很明显地求LIS,但是需要两个优化:
1.时间复杂度要为O(n*logn);
2.求出递增序列

1.普通的动态规划求法是用dp[i]表示以s[i]结尾的递增序列长度,但是这种方法的时间复杂度为O(n^2);
2.可以用B[i]表示长度为i的递增序列结尾元素是s[i];然后遍历一遍序列:
	B[i]<s[i]   : B[++len]=s[i];
	否则:找出B中第一个大于等于s[i]的元素下标f,标记为新的长度为f的递增序列;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*
单调递增序列 
WoAiLanQiaoAiBeiQiao
*/
vector<string>q;
string B[10010];
int pre[10010];
string ans[10010];
int serach_index(string B[],int len,string x){//求第一个>=x的值 
	int lef=1,rig=len;//??
	while(lef<rig){
		int mid=lef+rig >> 1;
		if(B[mid]<=x){
			rig=mid+1;
		}
		else lef=mid;
	}
	return lef;
}
int main(){
	string s;
	cin>>s;
	int last=0;
	for(int i=0;i<s.size()-1;i++){
		if(s[i+1]>='A'&&s[i+1]<='Z'){
			string name=s.substr(last,i-last+1);
			last=i+1; 
			q.push_back(name);
		}
	}
	q.push_back(s.substr(last,s.size()-1-last+1));
//	cout<<"q.size "<<q.size()<<endl;
	int l=q.size();
	int maxi,maxlen=0;
	int len=1;B[1]=q[0];
	pre[0]=1;//初始化 
	for(int i=1;i<l;i++){
		if(B[len]<q[i]){
			B[++len]=q[i];
			pre[i]=len;
		}
		else {
			//int f=serach_index(B,len,q[i]);//这个lower_bound有点意思
			int f=lower_bound(B+1,B+1+len,q[i])-B; 
			B[f]=q[i];
			pre[i]=f;
			//cout<<f<<endl;
		}
	}
//	for(int i=0;i<l;i++)
//		cout<<q[i]<<" "<<pre[i]<<endl;
	int temp=len;
	for(int i=l-1;i>=0;i--){
		if(pre[i]==len){
			ans[len]=q[i]; 
			len--;
		}
	}
	for(int i=1;i<=temp;i++)
		cout<<ans[i];
	return 0;
}

总结

我对LIS的总结

H.答疑

在这里插入图片描述
在这里插入图片描述

解题思路

设结果中的第i个请教的同学进入+答疑的时间是q[i],进入+答疑+离开的时间是p[i];
那么总时间是:q[1]+(p[1]+q[2])+(p[1]+p[2]+q[3])=2p[1]+p[2]+(q1+q2+q3);
所以就是按时间排序~~~;
在这里插入图片描述
代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*
5
2 435 76
34 57 78
676 8 87
587 78 8
346 767 66

*/
struct node{
	int w,s;
};
node stu[1005];
bool cmp(node a,node b){
	if(a.s!=b.s)
		return a.s<b.s;
	return a.w<b.w;
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		int a,b,c;
		cin>>a>>b>>c;
		stu[i].w=a+b;
		stu[i].s=stu[i].w+c;
	}
	sort(stu,stu+n,cmp);
	ll ans=0,temp=0;
	for(int i=0;i<n;i++){
		ans=ans+temp+stu[i].w;//上一个学生+当前需要用时 
		temp=temp+stu[i].s;//更新 
	//	cout<<ans<<endl;
	}
	cout<<ans<<endl;
	return 0;
}

总结

我考试的时候也是瞎猜,考完之后看大佬的题解,好像还蒙对了~~~;

I.

解题思路

总结

J.质数行者

在这里插入图片描述
在这里插入图片描述

解题思路

1.暴搜混分

考试的时候用的记忆化暴搜混分~
估计了时间,也就能过一个样例~
而且这题也不能用广搜,因为这题没有“层次性”;

代码展示

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5;
/*
1.记忆化搜索的前提是基本搜索
2.搞一搞牛逼筛法
3.暴力求稳 

A. Tit for Tat
*/
int vis[305][305][305];
vector<int>step;
bool Judge(int x){
	for(int i=2;i*i<=x;i++)
		if(x%i==0)return false;
	return true;
}
int len;
void init(){
	for(int i=2;i<=1000;i++){
		if(Judge(i))step.push_back(i);
	}
	len=step.size();
}
int n,m,w;
int ans;
int a1,b1,c1,a2,b2,c2;
bool Judge2(int x,int y,int z){
	if(a1==x&&b1==y&&c1==z)return 0;
	if(a2==x&&b2==y&&c2==z)return 0;
	return true;
}
int DFS(int x,int y,int z){//我他妈能把变量搞混~~~ 
	if(Judge2(x,y,z)==false)return 0;
	if(x==n&&y==m&&z==w){
		return 1;
	}
	int sum=0;
	for(int i=0;i<len;i++){
		if(x+step[i]<=n)
			sum+=DFS(x+step[i],y,z);
		if(y+step[i]<=m)
			sum+=DFS(x,y+step[i],z);
		if(z+step[i]<=w)
			sum+=DFS(x,y,z+step[i]);
	}
	vis[x][y][z]=sum;
	return sum;
}
int main(){
	init();
	cin>>n>>m>>w;
	cin>>a1>>b1>>c1;
	cin>>a2>>b2>>c2;
	cout<<DFS(1,1,1)<<endl;
	return 0;
}

总结

参考博客
https://blog.csdn.net/qq_20087731/article/details/109691930

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高冷小伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值