NWPU周赛题解

太久没做题了,做题做出来就是没感觉。

要么就是知道做,写不对;要么就是看不懂题,看懂了之后觉得很简单

哈夫曼树的简单模拟都不会了必须得使用C++的优先队列搞法,简直弱爆炸

————————————————————————————————————————————————————————————————

废话不多说,先来一发比赛链接

NWPU开学第一战


————————————————————————————————————————————————————————————————

A题是字符串的处理题似乎要用到kmp

C题是图论的题,暂时没思路先留空留在这,会了再说


————————————————————————————————————————————————————————————————

B题:

exgcd的基本题

注意题意的要求有两个:系数和尽量小,总砝码质量也尽量小

exgcd

上列了个exgcd的基本题链接,可以看到弱的代码


基本算法思想就不解释了,百度一大堆,注意这个题的方法。必须考虑到三种情况:

ax+by=m

-ax+by=m

ax-by=m

然后,就简单了


ll a,b,m,ansx,ansy,tot;
ll x,y,g,l,r,x1,x2;

ll exgcd(ll a,ll b,ll &x,ll &y){
	if (a==0&&b==0) return -1;
	if (b==0){
		x=1;y=0;return a;
	}
	ll d=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return d;
}

int main(){
	//input;
	while(scanf("%I64d%I64d%I64d",&a,&b,&m)!=EOF){
		if (a+b+m==0) break;
		tot=ansx=ansy=INF;
		tot*=99999999;

		g=exgcd(a,-1*b,x,y);
		x*=m/g;
		y*=m/g;
		l=b/g;if (l<0) l=-1*l;
		r=a/g;if (r<0) r=-1*r;
		x1=(x%l+l)%l;
		y=(y%r+r)%r;
		x2=(m+b*y)/a;
		for(x=x1;x<=x2;x+=l){
			y=(a*x-m)/b;
			if (y<0) continue;
			if (x+y<=ansx+ansy&&tot>=x*a+b*y){
				ansx=x;
				ansy=y;
				tot=x*a+b*y;
			}
		}
		
		g=exgcd(a,b,x,y);
		x*=m/g;
		y*=m/g;
		l=b/g;if (l<0) l=-1*l;
		r=a/g;if (r<0) r=-1*r;
		x1=(x%l+l)%l;
		y=(y%r+r)%r;
		x2=(m+b*y)/a;
		for(x=x1;x<=x2;x+=l){
			y=(m-a*x)/b;
			if (y<0) continue;
			if (x+y<=ansx+ansy&&tot>=x*a+b*y){
				ansx=x;
				ansy=y;
				tot=x*a+b*y;
			}
		}
		
		
		m=-1*m;
		g=exgcd(a,-1*b,x,y);
		x*=m/g;
		y*=m/g;
		l=b/g;if (l<0) l=-1*l;
		r=a/g;if (r<0) r=-1*r;
		x1=(x%l+l)%l;
		y=(y%r+r)%r;
		x2=(m+b*y)/a;
		for(x=x1;x<=x2;x+=l){
			y=(a*x-m)/b;
			if (y<0) continue;
			if (x+y<=ansx+ansy&&tot>=x*a+b*y){
				ansx=x;
				ansy=y;
				tot=x*a+b*y;
			}
		}
		printf("%I64d %I64d\n",ansx,ansy);
	}
	return 0;
}

————————————————————————————————————————————————————————————————

D题:

熟悉前缀和的,熟悉欧拉函数的,这个题就是个模板咯

直接上代码也能懂的

可以直接打表的随便搞法


LL euler[maxn+50];

void getEuler(){
	memset(euler,0,sizeof(euler));
	euler[1]=1;
	for(int i=2;i<=1000000;i++)
		if (!euler[i])
			for(int j=i;j<=1000000;j+=i){
				if (!euler[j]) euler[j]=j;
				euler[j]=euler[j]/i*(i-1);
			}
}

int main(){
	//freopen("input.txt","r",stdin);
	getEuler();
	for(int i=3;i<=maxn;i++)
		euler[i]+=euler[i-1];
	int n;
	//printf("%I64d\n",euler[maxn]);
	while(scanf("%d",&n)!=EOF){
		if (!n) break;
		printf("%I64d\n",euler[n]);
	}
	return 0;
} 

————————————————————————————————————————————————————————————————

E题:

看到题的数据量很开心,50*50的矩阵,可以随便搞

看懂题了之后觉得很恶心,怎么处理连通

找到了一个通法:dfs中,由从A格去B格的方向为基础判断

如:A去B的时候,方向为往右走,那么A的开口是必须有右的,B的开口是必须有左的,同理其他三个方向

(说是这么说还是得注意细节,我是用结构体,存储每个节点的开口)

那么这个题就变成了处理联通块个数的问题了(会dfs一定会这种题吧,嗯嗯,一定是)

唯一1A的题,麻烦的题就会尽力注意细节了


int n,m,ans;
char mp[maxn][maxn];
int col[maxn][maxn];

int dx[]={0,1,-1,0,0};
int dy[]={0,0,0,1,-1};

struct node{
	int u,l,r,d;
}Node[maxn][maxn];

void getdir(char ch,node &x){
	x.u=x.l=x.r=x.d=0;
	if (ch=='A') x.u=x.l=1;
	else if (ch=='B') x.u=x.r=1;
	else if (ch=='C') x.d=x.l=1;
	else if (ch=='D') x.d=x.r=1;
	else if (ch=='E') x.u=x.d=1;
	else if (ch=='F') x.l=x.r=1;
	else if (ch=='G') x.u=x.l=x.r=1;
	else if (ch=='H') x.u=x.d=x.l=1;
	else if (ch=='I') x.l=x.r=x.d=1;
	else if (ch=='J') x.r=x.u=x.d=1;
	else x.u=x.r=x.d=x.l=1;
	//printf("%d %d %d %d\n",x.u,x.r,x.l,x.d);
}

bool check(int x,int y,int nx,int ny,int dir){
	if (dir==1&&Node[x][y].d&&Node[nx][ny].u) return true;
	if (dir==2&&Node[x][y].u&&Node[nx][ny].d) return true;
	if (dir==3&&Node[x][y].r&&Node[nx][ny].l) return true;
	if (dir==4&&Node[x][y].l&&Node[nx][ny].r) return true;
	return false;
}

void dfs(int x,int y){
	for(int k=1;k<=4;k++){
		int nx=x+dx[k];
		int ny=y+dy[k];
		if (nx>=1&&nx<=n&&ny>=1&&ny<=m&&!col[nx][ny])
			if (check(x,y,nx,ny,k)){
				col[nx][ny]=ans;
				dfs(nx,ny);
			}
	}
}

int main(){
	//freopen("input.txt","r",stdin); 
	while(scanf("%d%d",&n,&m)!=EOF){
		ans=0;
		if (n==-1&&m==-1) break;
		memset(col,0,sizeof(col));
		for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				getdir(mp[i][j],Node[i][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				if (!col[i][j]){
					ans++;
					col[i][j]=ans;
					dfs(i,j);
				}
		printf("%d\n",ans);
	}
	return 0;
}

————————————————————————————————————————————————————————————————

F题:

直接让我想退役不想玩了的题

想做模拟的方法竟然不会写了

看完题,关键词any,就是说每次算完两个小的数之和再次排序再次取两个小的,那么:哈夫曼!

直接优先队列搞一发,每次取最小的两个呗


写了个优先队列的基本使用方法以及优先级的定义:

优先队列学习戳我


priority_queue<int,vector<int>,greater<int> > q;

int main(){
	//freopen("input.txt","r",stdin);
	int n,num,ans,num1,num2;
	while(scanf("%d",&n)!=EOF){
		ans=0;
		while(!q.empty()) q.pop();
		for(int i=1;i<=n;i++){
			scanf("%d",&num);
			q.push(num);
		}
		for(int i=1;i<n;i++){
			num1=q.top();
			q.pop();
			num2=q.top();
			q.pop();
			num=num1+num2;
			ans+=num;
			q.push(num);
		}
		printf("%d\n",ans);
	}
	return 0;
}

————————————————————————————————————————————————————————————————

G题:

数学想法题

所谓阶乘,需要去找到特殊的数:质数

要求数位最多,那么尽可能拆分才会最多:分解质因数

但是质数没法拆分:知道了2,3,5,7的处理方法

4,6,8,9怎么办?

尽可能用小的

一定要注意阶乘:9!=7!*8*9=7!*(2*2*2)*(3*3)=7!*3!*3!*2!

那么每个数字单独搞就好

细节:(wa了几发):n的范围:int存不下

直接字符串搞就好了的


int num[20];
int n,x;
char s[20];
int main(){
	//freopen("input.txt","r",stdin);
	while(scanf("%d",&n)!=EOF){
		scanf("%s",&s);
		memset(num,0,sizeof(num));
		for(int i=0;i<n;i++){
			x=s[i]-'0';
			if (x==2) num[2]++;
			else if (x==3) num[3]++;
			else if (x==4) num[3]++,num[2]+=2;
			else if (x==5) num[5]++;
			else if (x==6) num[5]++,num[3]++;
			else if (x==7) num[7]++;
			else if (x==8) num[7]++,num[2]+=3;
			else if (x==9) num[7]++,num[2]++,num[3]+=2;
		}
		for(x=7;x>=2;x--)
			if (num[x])
				while(num[x]){
					printf("%d",x);
					num[x]--;
				}
		puts("");
	}
	return 0;
}

————————————————————————————————————————————————————————————————

总结:

简单题需要保证好细节的1A

难题需要慢慢找回来节奏去学

不管怎么样,祝周末的蓝桥杯顺利

全部评论

相关推荐

不愿透露姓名的神秘牛友
07-02 17:58
点赞 评论 收藏
分享
06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
流浪的神仙:无恶意,算法一般好像都得9硕才能干算法太卷啦
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务