【NOIP1999普及组T1】Cantor表

现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…

输入:整数N(1≤N≤10000000)

这道题就是找规律

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
int heng[maxn];
int shu[maxn];
int n;
int main(){
	heng[1]=1;shu[1]=1,shu[2]=3;
	int t=4;
	for(int i=2;i<=1000;i++){
		if(i%2==0) heng[i]=heng[i-1]+1;
		else {
			heng[i]=heng[i-1]+t;
			t+=4;
		}
	}
	t=6;
	for(int i=3;i<=1000;i++){
		if(i%2==1) shu[i]=shu[i-1]+1;
		else {
			shu[i]=shu[i-1]+t;t+=4;
		}
	}
	cin>>n;
	int i,j;
	for(i=1;i<=1000;i++){
		if(heng[i]>=n&&shu[i]<=n||heng[i]<=n&&shu[i]>=n) break;
	} 
	if(heng[i]>shu[i]){
		j=n-shu[i]+1;
		i=i-(n-shu[i]);
		cout<<i<<"/"<<j<<endl;
	}
	else {
		j=n-heng[i]+1;
		i=i-(n-heng[i]);
		cout<<j<<"/"<<i<<endl;
	}
return 0;
}

  1219 -- 【NOIP1999普及组T2】回文数

若一个数(首位不为零)从左向右读与从右向左读都是一样,我们就将其称之为回文数。例如:给定一个 10进制数 56,将 56加 65(即把56从右向左读),得到 121是一个回文数。
  又如,对于10进制数87:
  STEPl:87+78=165; STEP2:165+561= 726;
  STEP3:726+627=1353; STEP4:1353+3531=4884
  在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。
  写一个程序,给定一个N(2 < n <= 16)进制数 M,求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出“Impossible!”

还算是比较简单的,注意细节

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
using namespace std;
//回文数 
int n,aa[501],b[501];
bool judge(int aa[]){
	for(int i=1;i<=aa[0];i++) if(aa[i]!=aa[aa[0]-i+1]) return false;
	return 1;
}
void init(){
	string s;
	cin>>n>>s;
	memset(aa,0,sizeof(aa));
	aa[0]=s.length();
	for(int i=1;i<=aa[0];i++){
		if(s[aa[0]-i]>='0'&&s[aa[0]-i]<='9') aa[i]=s[aa[0]-i]-'0';
		else aa[i]=s[aa[0]-i]-'A'+10; //16进制 
	} 
}
void jia(int aa[]){
	memset(b,0,sizeof(b));
	for(int i=1;i<=aa[0];i++) b[i]=aa[aa[0]-i+1];
	for(int j=1;j<=aa[0];j++) aa[j]+=b[j];
	for(int i=1;i<=aa[0];i++){
		aa[i+1]+=aa[i]/n;
		aa[i]%=n;
	}
	if(aa[aa[0]+1]>0) aa[0]++; //进位 
}
int main(){
	int ans=0;
	init();
	if(judge(aa)) {
		cout<<"STEP=0"<<endl;
		return 0;
	}
	while(ans<=30){
		ans++;
		jia(aa);
		if(judge(aa)){
			cout<<"STEP="<<ans<<endl;
			return 0;
		}
	} 
	cout<<"Impossible!"<<endl;
return 0;
}

  

1220 -- 【NOIP1999普及组T3】旅行家的预算

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,…,N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。

第一行为4个实数D1、C、D2、P与一个非负整数N;
  接下来N行,每行两个实数Di、Pi。

//一看到这个题就想到贪心

//思路:

//首先判断能不能开完:如果有两个加油站之间的距离大于满箱状态下能开的距离,No Solution 

//找后面第一个比此处价格更低的加油站

//如果能开过去,直接开过去。否则,如果加油后能开过去,就加上刚好能到那里的油

 

//如果即使加满油也开不过去,就先加满油,再找所及范围之内的价格最低的加油站开过去

区分三种情况,细节和逻辑

     #include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<cstdio>
#include<queue>
#include<map>
#include<vector>
#include<set>
using namespace std;
const int maxn=1010;
const int INF=0x3fffffff;
double dis,total,dis2,pri1;
int n;
double diss[100],mon[100],all;
//一看到这个题就想到贪心
//思路:
//首先判断能不能开完:如果有两个加油站之间的距离大于满箱状态下能开的距离,No Solution 
//找后面第一个比此处价格更低的加油站
//如果能开过去,直接开过去。否则,如果加油后能开过去,就加上刚好能到那里的油
//如果即使加满油也开不过去,就先加满油,再找所及范围之内的价格最低的加油站开过去
double go(int index,double x,double money){   //晕  写出int返回值,错了好久 
//分别是现在的位置、现在还能开的长度,需要的钱 
	if(index==n+1) return money;
	int pos=0;
	for(int i=index+1;i<=n+1;i++){
		if(mon[i]<mon[index]) { 
		pos=i;//找到第一个比此处价格低的加油站(贪心)
		break;
		 }
	}
	if(x>=diss[pos]-diss[index]){ //如果能够直接开过去
	return go(pos,x-(diss[pos]-diss[index]),money); 
	}
	else if(all>=diss[pos]-diss[index]){ //如果加油后能过去 ,就加刚好能过去的油 
	return go(pos,0,money+mon[index]*(diss[pos]-diss[index]-x)/dis2);
	//要算上加上油去那里的钱 
	}
	else {
		//所及范围之内的价格最低的加油站开过去
		int minn=INF;
		int next=0;
		for(int i=index+1;diss[i]-diss[index]<=all;i++){
			//加了油能过去的
			if(mon[i]<minn){
				minn=mon[i];
				next=i;
			}	
		}
		return go(next,all-(diss[next]-diss[index]),money+mon[index]*(all-x)/dis2); 
		//加上的钱是全部的路程减去能走的 
	}
}
int main(){
	cin>>dis>>total>>dis2>>pri1;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>diss[i]>>mon[i];
	diss[n+1]=dis;
	mon[n+1]=0; //把终点作为加油站
	all=total*dis2;
	diss[0]=0;mon[0]=pri1; //起点也加进来
	 
	for(int i=2;i<=n+1;i++){
		if(diss[i]-diss[i-1]>all) {
			cout<<"No Solution"<<endl;
			return 0;
		}
	}
	printf("%.2lf\n",go(0,0,0));
return 0;
}

  

 

 

 

 

 

 

 

现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…

 posted on 2020-04-19 21:31  shirlybabyyy  阅读(227)  评论(0编辑  收藏  举报