一. 程序题(共1题,100分)
- (程序题)
N:自然数, Q:有理数,构造双射函数(双射函数概念请看离散数学)
输入:多行,每行两个整数a和b,中间有一个空格,表示一个有理数a/b
输出:对应的多行,每行一个整数,有理数a/b的双射函数对应的自然数,结果<500000
输入样例:
-2 1
-4 1
-1 2
输出样例:
5
19
3
解题思路:看到箭头我就想到走迷宫,走迷宫要定义上下左右四个方向,而此题也类似,观察图像我们可以知道箭头的方向是8次一个循环。如图:
所以我们和图示一样构造8个方向的操作,那么问题的关键来了,我们什么时候换方向呢?仔细观察不难发现,需要改变方向时我们会碰到的坐标分别是x/1 ,x属于整数,以及,1/2 ,-1/2, -2/3 ,2/3…,这些都是很容易找规律的坐标点,我们需要按照图中方向的顺序来依次保存他们,值得注意的是x/1是非常特殊的坐标,我们不需要保存,只需要当y=1时就变向即可,而且变向后向前的步数为1。如此我们根据这个规律就可以找到足够多的x/y的数据,每次获得一个x/y,利用一个set来保存x➗y的值,将set的size()用来记录x/y右上角的唯一编号。有了这个思路我们就能写出代码了。
代码如下:
#include<bits/stdc++.h>
using namespace std;
double x = 0;
double y = 1;
int times = 0;
int n = 0;
int len = 0;
double xx ;
double yy ;
double x2;
double y2;
set<double> res;//上标
pair<pair<int,int>,int> res6[755555];//不能用map,map太耗时
int odd = 2;
const int N =1200;
//记录所有的中转点
pair<int, int> xy[N];
void init(){
int a1 = 1;
int a2 = 2;
int k = 0;
int i = 0;
while(k < N/2){
if(odd%2==0){
xy[i].first = a1;
xy[i].second = a2;
i++;
xy[i].first = -a1;
xy[i].second = a2;
i++;
a1++;
a2++;
k++;
odd++;
}else{
xy[i].first = -a1;
xy[i].second = a2;
i++;
xy[i].first = a1;
xy[i].second = a2;
i++;
a1++;
a2++;
k++;
odd++;
}
}
}
//定义8次循环的操作
void op(int i){
if(i==1){
x++;
res.insert(x/y);
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
// cout<<x<<" "<<y;
// cout<<endl;
}else if(i==2){
x2 = xy[n].first;
y2 = xy[n].second;
// cout<<"----"<<x1<<" "<<y1;
// cout<<endl;
n++;
while(true){
if(y<y2){
y++;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break1---";
break;
}
}
}else if(i == 3 ){
x2 = xy[n].first;
y2 = xy[n].second;
// cout<<"----"<<x1<<" "<<y1;
// cout<<endl;
n++;
while(true){
if(x>x2){
x--;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break2---";
break;
}
}
}else if(i==4){
while(true){
if(y>1){
y--;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break3---";
break;
}
}
}else if(i==5){
x--;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else if(i==6){
x2 = xy[n].first;
y2 = xy[n].second;
// cout<<"----"<<x1<<" "<<y1;
// cout<<endl;
n++;
while(true){
if(y<y2){
y++;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break4---";
break;
}
}
}else if(i == 7){
x2 = xy[n].first;
y2 = xy[n].second;
// cout<<"----"<<x1<<" "<<y1;
// cout<<endl;
n++;
while(true){
if(x<x2){
x++;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break5---";
break;
}
}
}else if(i==8){
while(true){
if(y>1){
y--;
res.insert(x/y);
// cout<<x<<" "<<y;
// cout<<endl;
res6[len].first = {x,y};
res6[len].second = res.size()-1;
len++;
}else{
// cout<<"break6---";
break;
}
}
}
}
int main(){
init();
int i ;
//循环获得足够多的x/y数据
while(true){
times++;
i=1;
for(;i<=8;i++){
op(i);
}
if(times>299) break;
}
//输出结果
while(~scanf("%lf %lf",&xx,&yy)){
for(int w = 0 ; w < len ; w++){
if(res6[w].first.first == xx &&res6[w].first.second == yy ){
printf("%d\n",res6[w].second);
break;
}
}
}
return 0;
}
还有就是别直接黏贴复制,学习通会判0分的。
点点赞吧!