NWPU周赛题解

来源:互联网 发布:数据库实训总结 编辑:程序博客网 时间:2024/05/17 22:49

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

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

哈夫曼树的简单模拟都不会了必须得使用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

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

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

0 0
原创粉丝点击