【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 ",go(0,0,0)); return 0; }
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:
我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…