哈尔滨理工大学软件与微电子学院程序设计竞赛 题解

news/2024/7/8 3:08:59

DEF题比较难一些,目前本菜鸡能力有限。

文章目录

    • A-Race
    • B-Min Value
    • C-Coronavirus
    • G-OXR
    • H-Maze
    • I-Prime
    • J-Compare
    • K-Walk
    • L-Defeat the monster

A-Race

题解:
我们可以看到数据量并不是很大,所以我们可以选择一秒钟一秒钟来对这个比赛进行分析
在每一秒中
要判断
1.是否有人到达终点
2.小明与小红之间的距离

代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e6+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;int main()
{int va,vr,t,s,l;cin>>va>>vr>>t>>s>>l;int ming=0,hong=0;int cnt=0;while(true){if(hong>=l&&ming>=l){cout<<"Tie "<<cnt<<endl;break;}else if(hong>=l&&ming<l){cout<<"Hong "<<cnt<<endl;break;}else if(hong<l&&ming>=l){cout<<"Ming "<<cnt<<endl;break;}if(ming-hong>=t){int zz=0;while(zz<s){zz++;cnt++;hong+=vr;if(hong>=l){cout<<"Hong "<<cnt<<endl;return 0;}}}cnt++;hong+=vr;ming+=va;}return 0;
}

B-Min Value

题解:
这个题他要求数组内相加差值最小的数,我的思路是排序+双指针。
但是这个双指针的内部操作有几点是要注意的。
1.排序:如何排序?
我们先按照元素大小进行排序,再按照其下表进行排序,为什么第二点要按照下标进行排序,后面我会说一下。
2.双指针:
首先我们用l指针指向排好序的第一个元素,再用r指针指向排好序的最后一个元素。
之后我们不断的从两边往中间夹。
(1)首先我们把元素相加的绝对值给算出来,看看他是不是目前最小的,如果不是就更新当前最小及其下标之和,如果跟当前最小值相等的话,那么就检查一下看看是否可以更新下表之和的最小值。
(2)如何判断该移动哪个指针呢。
如果两者之和小于0那么我们就把左指针往右移动
如果两者之和大于0那么我们就把右指针往左移动

下面我们看一个样例:

5 
-1 -1 0 1 1

这个样例该如何移动?
我们前面排序的方法是如果元素值相同就按照其下表进行排序
所以如果相加等于0,那么我们只需要把右指针往左移动即可,因为只有把右指针往左移动,才能减少其下表最小值

重点:
那么我们再看题目给的样例

5
-2 6 7 7 -8

我们发现排好序后是,下面的数代表他的初始下表

-8 -2 6 7 7
5   1 2 3 4

很明显-8跟到数第二个7组合会得到最优解。
既然这样的话,我们就根本不需要特判左端点元素值+右端点元素值相等的时候在移动右端点,有可能元素和最优解并不是的0,所以在判断如何移动的时候,我们先进行判断右端点是否跟右端点-1的值相同,如果相同就移动右端点,因为越靠左边下标越小
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
struct wazxy{int val,pos;
}a[maxn];
struct rule{bool operator()(const wazxy & a,const wazxy & b){if(a.val!=b.val) return a.val<b.val;else return a.pos<b.pos;}
};
int main()
{int n;cin>>n;for(int i=1;i<=n;i++){scanf("%d",&a[i].val);a[i].pos=i;}sort(a+1,a+n+1,rule());int l=1,r=n;int imin=MaxN,ans;while(l<r){//cout<<"L:"<<l<<" "<<r<<endl;int sum=abs(a[l].val+a[r].val);if(sum<imin) imin=sum,ans=a[l].pos+a[r].pos;else if(sum==imin) ans=min(ans,a[l].pos+a[r].pos);if(a[r].val==a[r-1].val)  r--;else if(a[l].val+a[r].val>=0)  r--;else if(a[l].val+a[r].val<0) l++;}cout<<imin<<" "<<ans<<endl;return 0;}

C-Coronavirus

题解:
简单的bfs,我们可以将高位地段周围的八个区域全都给标记为不能走的区域,其实就相当于放上了一堵墙,不过这个放墙的过程可真谓是坑多多。
1.假如你把它旁边的墙标记为‘’,那你样例都过不了,因为隔壁的‘’还会被当成新的一个危险区域,并且扩散至周围。。
2.所以你应该把它周围的换一种标价来标。
3.接着第二个问题,如果你直接把他周围的地区给标记为你自己设置的符号,那如果周围也是一个危险区域,你直接把这个危险区域覆盖住了,这也是不可以的,所以需要判断周围的符号是不是‘*’,如果是的话就不需要标记了。
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 55;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
char a[maxn][maxn];
bool visited[maxn][maxn];
int n,m;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
bool flag=false;
int mins;
struct wazxy{int x,y,steps;wazxy(int a,int b,int c){x=a,y=b,steps=c;}
};bool bfs(int x,int y){queue<wazxy> q;visited[x][y]=true;q.push(wazxy(x,y,0));while(!q.empty()){//cout<<"de"<<endl;wazxy temp=q.front();q.pop();if(a[temp.x][temp.y]=='E'){mins=temp.steps;return true;}for(int i=0;i<4;i++){int nx=temp.x+dx[i];int ny=temp.y+dy[i];if((a[nx][ny]=='.'||a[nx][ny]=='E')&&!visited[nx][ny]){visited[nx][ny]=true;q.push(wazxy(nx,ny,temp.steps+1));}}}return false;
}int main()
{cin>>n>>m;memset(a,-1,sizeof(a));memset(visited,false,sizeof(visited));for(int i=1;i<=n;i++){scanf("%s",a[i]+1);}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]=='*'){if(a[i+1][j]!='*')a[i+1][j]=-1;if(a[i][j+1]!='*')a[i][j+1]=-1;if(a[i-1][j]!='*')a[i-1][j]=-1;if(a[i][j-1]!='*')a[i][j-1]=-1;if(a[i+1][j-1]!='*')a[i+1][j-1]=-1;if(a[i+1][j+1]!='*')a[i+1][j+1]=-1;if(a[i-1][j+1]!='*')a[i-1][j+1]=-1;if(a[i-1][j-1]!='*')a[i-1][j-1]=-1;}}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]=='E') flag=true;}}if(flag==false){cout<<"Impossible"<<endl;return 0;}//cout<<"de"<<endl;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i][j]=='S')flag=bfs(i,j);}}if(flag) cout<<mins<<endl;else cout<<"Impossible"<<endl;return 0;
}

G-OXR

思维题
题解:
因为是异或的计算
我们假设输入了一个10
它对应的二进制是:
1010
那么1-10来说,一共有10中对应的二进制
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
总有一个二进制数可以补齐1010 中0的位置
所以我们直接将1010补位1111输出对应的十进制即可
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 55;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;int main()
{long long n;cin>>n;if(n==1){cout<<0<<endl;return 0;}long long x=1;while(x<=n){x*=2;}cout<<x-1<<endl;return 0;
}

H-Maze

题解:
数据范围式1e7所以感觉尽量还是用一下欧拉筛吧,毕竟时间复杂度越低越好。
用visited数组记录,我们用前缀和来处理一下前i个数的质数个数,之后再O(1)的复杂度情况下即可查出。

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e7;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
bool visited[maxn+10];
int prim[1000000+5];
int ans[maxn+10];
void ispirm(){int cnt=0;memset(visited,true,sizeof(visited));for(int i=2;i<=maxn;i++){if(visited[i]) prim[cnt++]=i;for(int j=0;j<cnt&&prim[j]*i<=maxn;j++){visited[prim[j]*i]=false;if(i%prim[j]==0) break;}}
}
int main()
{ispirm();int t;cin>>t;for(int i=2;i<=maxn;i++){ans[i]=ans[i-1]+visited[i];}while(t--){int x,y;scanf("%d%d",&x,&y);printf("%d\n",ans[y]-ans[x-1]);}return 0;
}

I-Prime

题解:
数据范围式1e7所以感觉尽量还是用一下欧拉筛吧,毕竟时间复杂度越低越好。
用visited数组记录,我们用前缀和来处理一下前i个数的质数个数,之后再O(1)的复杂度情况下即可查出。
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e7;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
bool visited[maxn+10];
int prim[1000000+5];
int ans[maxn+10];
void ispirm(){int cnt=0;memset(visited,true,sizeof(visited));for(int i=2;i<=maxn;i++){if(visited[i]) prim[cnt++]=i;for(int j=0;j<cnt&&prim[j]*i<=maxn;j++){visited[prim[j]*i]=false;if(i%prim[j]==0) break;}}
}
int main()
{ispirm();int t;cin>>t;for(int i=2;i<=maxn;i++){ans[i]=ans[i-1]+visited[i];}while(t--){int x,y;scanf("%d%d",&x,&y);printf("%d\n",ans[y]-ans[x-1]);}return 0;
}

J-Compare

题解:
模拟水题。
1.首先先判断他的位数。
2.如果位数相同的话,我们就可以从头道尾进行比较了,正好string类的比较方式跟这个是相同的。

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 1e6+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;string a,b;
int main()
{cin>>a>>b;if(a.size()>b.size()) cout<<">"<<endl;else if(a.size()==b.size()){if(a>b) cout<<">"<<endl;else if(a<b) cout<<"<"<<endl;else cout<<"="<<endl;}else if(a.size()<b.size()) cout<<"<"<<endl;return 0;
}

K-Walk

题解:
这个路径的最短方法也就是跟高中学过的排列组合公式一样,但是目前的问题是这个数字十分大,应该如何解决呢?
当然是逆元的思想了。
拿了我之前博客的一张图,这个是结论(菜鸡我就直接用了)
在这里插入图片描述所以C(m+n-2,n-1)
比如说C(5,2)
=(5×4)/(2×1)
=(5×4×3×2×1)/(3×2×1×2×1)
所以得出以下结论:

fac[n]*quick(fac[n-m],mod-2)%mod*quick(fac[m],mod-2)%mod;

代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 2e6+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 1e9+7;
using namespace std;int fac[maxn];
int quick(int a,int n){int res=1;while(n){if(n&1) res=1ll*a*res%mod;a=1ll*a*a%mod;n>>=1;}return res;
}int C(int n,int m){return 1ll*fac[n]*quick(fac[n-m],mod-2)%mod*quick(fac[m],mod-2)%mod;
}int main()
{fac[0]=1;for(int i=1;i<=1000000+5;i++){fac[i]=1ll*fac[i-1]*i%mod;}int t;cin>>t;while(t--){int n,m;scanf("%d%d",&n,&m);printf("%d\n",C(n+m-2,n-1));}return 0;
}

L-Defeat the monster

题解:
我们可以先把他按照能力值水平由小到大进行排序,在进行双指针操作,我们每次都让右指针每次都移动,如果相差大于5的话我们就把左指针往右移动一下,并且如果(右指针指针指向的数-左指针指向的数)小于5的话,我们需要更新一下之间的差值。
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 2e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;int a[maxn];
int main()
{int n;cin>>n;for(int i=0;i<n;i++) scanf("%d",&a[i]);sort(a,a+n);int ans=0,l=0;for(int i=0;i<n;i++){if(a[i]-a[l]<=5){ans=max(ans,i-l+1);}else l++;}cout<<ans<<endl;return 0;
}

http://lihuaxi.xjx100.cn/news/285777.html

相关文章

来看看如何在 C# 中使用反射

C# 中的 反射 常用于在程序的运行时获取 类型 的元数据&#xff0c;可获取的信息包括已加载到进程中的 程序集 和 类型 信息&#xff0c;它和 C 中的 RTTI(Runtime Type Information) 的作用是差不多的。 C# 中的 反射 常用于在程序的运行时获取 类型 的元数据&#xff0c;可获…

我生于1997,我骄傲了吗?

本文经授权转载自公众号“图图是道”&#xff08;TTSD-TTSD&#xff09;1997&#xff0c;回归那年我出生在香港一户普普通通的家庭里爸爸给我起名嘉运他说既为了欢庆回归也为了庆祝度过金融风暴我小时候特别爱去海洋公园因为那有“安安”和“佳佳”妈妈说大熊猫是我们的国宝200…

HDU2675(二分算法)

题意&#xff1a;根据X^(eY) (eY)^ 求解X,使得满足该等式&#xff1a; &#xff08;1&#xff09;首先等式两边同时取对数&#xff1a;eYln(x)xln(eY); &#xff08;2&#xff09;继续化简&#xff1a;eYln(x)x(1ln(Y)); 根据上面推导的等式利用二分算法进行求解。 #include&…

这些 Shell 分析服务器日志命令集锦,收藏好

自己的小网站跑在阿里云的ECS上面,偶尔也去分析分析自己网站服务器日志,看看网站的访问量。看看有没有黑阔搞破坏&#xff01;于是收集&#xff0c;整理一些服务器日志分析命令&#xff0c;大家可以试试&#xff01;1、查看有多少个IP访问&#xff1a; awk {print $1} log_fil…

python大作业 学生管理系统 以Excel(xls)格式导入文件

简单的说一下每个板块的作用 这个load函数&#xff0c;是导入进来文件的数据 def load():dataxlrd.open_workbook(data.xls)tabledata.sheets()[0]ntable.nrowsfor i in range(0,n):stu.append(table.row_values(i))print(stu)然后我们看这个save_data的函数&#xff0c;因为…

用Python解锁“吃鸡”正确姿势

大吉大利&#xff0c;今晚吃鸡~ 今天跟朋友玩了几把吃鸡&#xff0c;经历了各种死法&#xff0c;还被嘲笑说论女生吃鸡的100种死法&#xff0c;比如被拳头抡死、跳伞落到房顶边缘摔死 、把吃鸡玩成飞车被车技秀死、被队友用燃烧瓶烧死的。这种游戏对我来说就是一个让我明白原来…

MySQL主从同步问题集

http://blog.chinaunix.net/uid-8786588-id-3771613.html在InnoDB引擎下发现&#xff0c;Mysql的主从热备存在数据不一致的问题&#xff0c;一些数据没有成功同步到备机。在use databases后&#xff0c;更新的表必须是当前选择的database才同步。譬如连上Mysql服务后操作&#…

我被裁员了!让保安把身患绝症的我被强赶出公司,亲身经历的噩梦!

本文转载自公众号&#xff1a;你的游戏我的心&#xff0c;希望能帮作者发个声&#xff0c;希望能有更多的人关注这件事&#xff0c;也希望作者维权成功、早日康复。我是网易的一名游戏策划。14年从上海交大毕业后就进入网易工作&#xff0c;5年里&#xff0c;我和大部分网易员工…