错误票据
//某涉密单位下发了某种票据,并要在年终全部收回。
//每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。
//因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。
//你的任务是通过编程,找出断号的ID和重号的ID。
//假设断号不可能发生在最大和最小号。
//要求程序首先输入一个整数N(N < 100)表示后面数据行数。
// 接着读入N行数据。
// 每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
// 每个整数代表一个ID号。
// 要求程序输出1行,含两个整数m n,用空格分隔。
// 其中,m表示断号ID,n表示重号ID
//样例一:
//输入
//2
//5 6 8 11 9
//10 12 9
//输出
//7 9
//样例二:
//输入
//6
//164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
//172 189 127 107 112 192 103 131 133 169 158
//128 102 110 148 139 157 140 195 197
//185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
//149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
//113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119
//输出
//105 120
//资源约定:
//峰值内存消耗 < 64M
// CPU消耗 < 1000ms
// 请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
// 所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
// 注意 : main函数需要返回0
// 注意 : 只使用ANSI C / ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
// 注意 : 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
// 提交时,注意选择所期望的编译器类型。
#include<iostream>
#include <sstream>
#include <algorithm>
#include<string>
using namespace std;
int line;
int ID[10000] = { 0 };
void sti(string &str,int &num)//可以直接用sstream引入stringstream字符串数据流,来实现字符串转换成数子(string to int(sti))//#include <cstdlib> ==int atoi (const char * str);
{
stringstream ss;
ss << str;
ss >> num;
}
int main()
{
scanf("%d", &line);
getchar();//能够录入回车
int n = 0;
for (int i = 0; i < line; i++)
{
string s;
getline(cin, s);//按行读取数据(cin接受空格输入)
istringstream iss(s);//s转化成字符串到iss
string tmp;
while (getline(iss, tmp, ' '))//按空格位置分割,拷贝到临时字符串变量tmp
{
sti(tmp,ID[n++]);//将tmp转成整形,并依次拷贝到data[]
}
}
sort(ID, ID + n);//data从小到大排序
int a, b;
for (int i = 0; i < n; i++)
{
if (ID[i] == ID[i + 1] - 2)//断层
a = ID[i] + 1;
if (ID[i] == ID[i + 1])//重复
b = ID[i];
}
printf("%d %d", a, b);
return 0;
}
带分数
//100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
//还可以表示为:100 = 82 + 3546 / 197。
//(有规律714*(100-3)=69258;197*(100-82)=3546)
//注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。(全排列)
//类似这样的带分数,100 有 11 种表示法。
//题目要求:
//从标准输入读入一个正整数N(N < 1000 * 1000)
//程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
//注意:不要求输出每个表示,只统计有多少表示法!
//解题:生成1至9的全排列,先在可能的位置插入+,再在可能的位置插入/,验算等式,做计算
//样例一:
// 用户输入:
//100
//程序输出
//11
//样例二:
//用户输入:
//105
//程序输出:
//6
#include<iostream>
#include<string>
#include<sstream>
#include <algorithm>
//#include<cstdlib>
using namespace std;
int ans=0;
void sti(string &str, int &num)//可以直接用sstream引入stringstream字符串数据流,来实现字符串转换成数子(string to int(sti))//#include <cstdlib> ==int atoi (const char * str);
{
stringstream ss;
ss << str;
ss >> num;
}
//int PART(const char *str, int position, int length)//循环地substr截取易导致超时,PART代替substr
//{
// int RETURN = 0;
// int t = 1;
// for (int i = position+length-1; i >=position; i--)
// {
// RETURN += (str[i] - '0') * t;
// t *= 10;
// }
// return RETURN;
//}
int N;
int main()
{
scanf("%d", &N);
string s = "123456789";
do
{ //const char *str=s.c_str();
for (int i = 1; i <= 7; i++)//插入+,+最大插到7(给/预留位置)
{
string a = s.substr(0,i);//+前的串的长度为i //=int inta=PART(str,0,i); //
int inta;//=int inta=atoi(a,c_str()); //
sti(a,inta);// //
if (inta>=N)
{
break;
}
for (int j = 1; j <= 9-i-1; j++)//返回j+1之后的值
{
string b = s.substr(i, j);//+与/之间串的长度为j-i //=int intb=PART(str,i,j);
string c = s.substr(i + j);///之后的串的长度为9-j-i //=int intc=PART(str,i+j,9-j-i);
int intb;//=int intb=atoi(b,c_str()); //
int intc;//=int intc=atoi(c,c_str()); //
sti(b, intb);// //
sti(c, intc);// //
if (inta+intb/intc==N&&intb%intc==0)//符合条件(需要能整除,因为整数加减乘除会四舍五入)
{
ans++;
printf("%d %d %d\n", inta, intb, intc);//验证
}
}
}
}
while (next_permutation(s.begin(),s.end()));//全排列
printf("%d", ans);
return 0;
}
第39级台阶
//小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
//站在台阶前,他突然又想着一个问题:
//如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?
//请你利用计算机的优势,帮助小明寻找答案。
//递归解题(二叉树)
#include<stdio.h>
int sum;
void f(int n,int step)
{
if (n < 0)
{
return;
}
if (n == 0 && step % 2 == 0)
{
sum++;
}
f(n - 1, step + 1);
f(n - 2, step + 1);
}
int main()
{
f(39, 0);
printf("%d", sum);
return 0;
}//斐波那契函数//
翻硬币
//小明正在玩一个“翻硬币”的游戏。
//桌上放着排成一排的若干硬币。我们用* 表示正面,用 o 表示反面(是小写字母,不是零)。
//比如,可能情形是:**oo***oooo
//如果同时翻转左边的两个硬币,则变为:oooo***oooo
//现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币, 那么对特定的局面,最少要翻动多少次呢?
//我们约定:把翻动相邻的两个硬币叫做一步操作。
// 输入
//两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度 < 1000
// 输出
//一个整数,表示最小操作步数。
// 用户输入:
// *o**o***o***
// *o***o**o***
// 应输出:
// 1
// 再例如:
// 用户输入:
// **********
// o****o****
// 应输出:
// 5
//易知出现不同位置的次数必为偶数(奇数无解)
//规律有最小操作步数=两相近的不同位置的脚标差的总和
#include<iostream>
#include<string>
using namespace std;
int main()
{
string original;//初始状态
string target;//目标状态
getline(cin, original);
getline(cin, target);
int LONG = original.length();
int start = -1;
int ans = 0;
for (int i = 0; i < LONG; i++)
{
if (original[i] != target[i])
{
if (start==-1)//还未标记第一个不同的位置
{
start = i;//找到第一个不同的位置,给它标记脚标
}
else//第一个不同的位置已经标记,现找到第二个不同的位置i
{
ans += (i - start);
start = -1;
}
}
}
cout << ans << endl;
return 0;
}
高数日记
//大数学家高斯有个好习惯:无论如何都要记日记。
//他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210
//后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?
//高斯出生于:1777年4月30日。
//在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。
//高斯获得博士学位的那天日记上标着:8113
//请你算出高斯获得博士学位的年月日。
//提交答案的格式是:yyyy - mm - dd, 例如:1980 - 03 - 21
#include<stdio.h>
int LEAPYEAR(int year)
{
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
return 1;
else
return 0;
}
int main()
{
int year = 1777;
int mounth = 4;
int day = 30;
for (int i = 0; i < 5343 - 1; i++)//由5343验证得 1777年4月30日 算一天,故-1
{
day++;
if (mounth == 12 && day == 32)
{
year++;
mounth = 1;
day = 1;
continue;
}
if ((mounth == 1 || mounth == 3 || mounth == 5 || mounth == 7 || mounth == 8 || mounth == 10) && day == 32)
{
mounth++;
day = 1;
continue;
}
if ((mounth == 4 || mounth == 6 || mounth == 9 || mounth == 11) && day == 31)
{
mounth++;
day = 1;
continue;
}
if (mounth == 2 && LEAPYEAR(year) && day == 30)
{
mounth++;
day = 1;
continue;
}
if (mounth == 2 && !LEAPYEAR(year) && day == 29)
{
mounth++;
day = 1;
continue;
};
}
printf("%d %d %d", year, mounth, day);
return 0;
}
黄金分割数
//黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
//对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
//言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
//比较简单的一种是用连分数:
// 1
// 黄金数 = ---------------------
// 1
// 1 + -----------------
// 1
// 1 + -------------
// 1
// 1 + ---------
// 1 + ...
// (斐波那契数列的相邻两项之比)
//这个连分数计算的“层数”越多,它的值越接近黄金分割数。
//请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
//小数点后3位的值为:0.618
//小数点后4位的值为:0.6180
//小数点后5位的值为:0.61803
//小数点后7位的值为:0.6180340
//(注意尾部的0,不能忽略)
//你的任务是:写出精确到小数点后100位精度的黄金分割值。
//注意:尾数的四舍五入! 尾数是0也要保留!
//(层数增加,小数点后101为不变)
//(小数点位数太长,不能用c语言定义运算,只能手工的写大数运算)
#include<iostream>
#include <string>
#include <algorithm>
#include <sstream>
using namespace std;
int n = 400;//测试n相是否符合要求,调大n值,直到后100位稳定
void its(int &num, string &str)//可以直接用sstream引入stringstream字符串数据流,来实现数字转换成字符串(int to string(its))//#include <cstdlib> =char *itoa(int value, char *string, int radix);
{
stringstream ss;
ss << num;
ss >> str;
}
string add(string a, string b) //大数加法
{
a = a.substr(a.find_first_not_of('0'));
b = b.substr(b.find_first_not_of('0'));
long long lena = a.length();
long long lenb = b.length();
long long len = max(lena, lenb) + 10;
//求和的最大长度(+10为了进位)
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
//翻转,便于低位求和
string ans(len, '0');
for (int i = 0; i < lena; i++)
{
ans[i] = a[i];
}
int tmp = 0;//记录进位的“1”
for (int i = 0; i < len; i++)
{
if (i<b.length())
{
tmp += (ans[i] - '0') + (b[i] - '0');
//字符减'0'可以到相应的整数。现在比如我们要字符‘1’转换成数字1,就这么一个变化,我们看到了大家注意了字符型常量用''括起来的原因是,它们在计算机中都以各自的ASCII表示。
//而‘1’的对应编码是49的二进制码,但是我们的数字1,就等于1呀,所以为了由原来的‘1’实际上就是49的二进制变成现在的1对应的二进制1,只好用49 - 48 = 1了。
//但是在ASCII码里‘0’对应的刚好是48的二进制码,所以我们转换的时候只需要‘1’ - ‘0’ = 1;就可以了。而数字的ASCII码是按顺序规定的。所以其它字符要转换成数字都可以用减‘0’来表示。
//比如‘2’的ASCII是50,而我们要得到数字2,于是用‘2’ - 48 = 2了。
//大小写字母的转换:先看ASCII码:a~z是97~122的二进制,而A~Z是65~90的二进制编码,于是我们就得出:大写字母 = 小写字母 - 32 ;。当然这里的32我也可以这么写‘Z’ = ‘z’ - '空格'(空格的ASCII码是32).
}
else
{
tmp += (ans[i] - '0');
}
ans[i] = tmp % 10+'0';//+‘0’转回字符
tmp /= 10;//等于1
}
reverse(ans.begin(), ans.end());
return ans.substr(ans.find_first_not_of('0'));
}
int compare(string a, string b)
{
unsigned long i1 = a.find_first_not_of('0');
if (i1 == string::npos)a = '0';
else a.substr(i1);
unsigned long i2 = b.find_first_not_of('0');
if (i2 == string::npos)b = '0';
else b.substr(i2);
if (a.length() > b.length())
{
return 1;
}
else if (a.length() < b.length())
{
return -1;
}
else//长度相等,大小不等
{
if (a < b)
{
return -1;
}
if (a > b)
{
return 1;
}
else
return 0;
}
}
string subtract(string a, string b)//此时a>b
{
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
for (int i = 0; i < b.length(); i++)
{
if (a[i] >= b[i])
{
a[i] = a[i] - b[i] + '0';
}
else//借位
{
int k = 1;
while (a[i + k] == '0')
{
a[i + k] = '9';
k++;
}
a[i + k] = a[i + k] - '1' + '0';
a[i] = (a[i] - '0' + 10) - (b[i] - '0')+'0';
}
}
reverse(a.begin(), a.end());
if (a.find_first_not_of('0') == string::npos)
return "0";
return a.substr(a.find_first_not_of('0'));
}
string divide(string a, string b)//大数除法→转换成减法
//易知a<b
{
string ans = "0.";
for (int i = 0; i < 101; i++)
{
a.append("0");//补“0”
int t=0;
while (compare(a, b) >= 0)//a>b时,不停地作减法
{
a = subtract(a, b);
t++;//记录减法次数
}
string a;
its(t, a);
ans.append(a);
}
return ans;
}
int main()
{
string a = "1";
string b = "1";
for (int i = 3; i <=n; i++)
{
string tmp = b;
b = add(a, b);
a = tmp;
//a,b是斐波那契数列的n和n+1相
}
string ans = divide(a, b);
cout << ans << endl;//结果保留100位小数
cout << ans.length() - 2 << endl;//小数点算一位
return 0;
}
连号区间数
//小明这些天一直在思考这样一个奇怪而有趣的问题:
//在 1 ~ N 的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
//如果区间[L, R]里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R ? L + 1 的 “连续” 数列,则称这个区间连号区间。
//当 N 很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
//输入格式
//第一行是一个正整数 N(1 ≤ N ≤ 50000),表示全排列的规模。
//第二行是 N 个不同的数字 P i(1 ≤ P i ≤ N),表示这 N 个数字的某一全排列。
// 输出格式
// 输出一个整数,表示不同连号区间的数目。
// 样例输入一:
// 4
// 3 2 4 1
// 样例输出一:
// 7
// 样例输入二:
// 5
// 3 4 2 5 1
// 样例输出二:
// 9
//样例一解释:7个连号区间是:[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4]→{(3),(2,3),(2,3,4),(1,2,3,4),(2),(4),(5)}各括号内的数能组成长度为R - L + 1 的 “连续” 数列
//样例一解释:9个连号区间是:[1,1],[1,2],[1,3],[1,4],[1,5],[2,2],[3,3],[4,4],[5,5]
//脚标之差等于对应数列的极差
#include<iostream>
using namespace std;
int N;
int array[50000];
int ans = 0;
int main()
{
scanf("%d", &N);//输入全排列规模
for (int i = 0; i < N; i++)//输入数组
{
scanf("%d", &array[i]);
}
for (int i = 0; i < N; i++)//L
{
int min = array[i];
int max = array[i];
for (int j = i; j < N; j++)//R
{
if (array[j] >= max)
{
max = array[j];
}if (array[j] <= min)
{
min = array[j];
}
if (i == j)//长度为1的数量必连续
{
ans++;
}
else//else是相邻if的else
{
if (max - min + 1 == j - i + 1)//符合规律
{
ans++;
}
else
{
continue;
}
}
printf("%d %d %d\n", i, j, ans);
}
}
printf("%d", ans);
return 0;
}
马虎的计算
//小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。
//有一次,老师出的题目是:36 x 495 = ?
//他却给抄成了:396 x 45 = ?
//但结果却很戏剧性,他的答案竟然是对的!!
//因为 36 * 495 = 396 * 45 = 17820
//类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54
//假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)
//能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?
//请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。
#include<stdio.h>
int main()
{
int sum = 0;
for (int a = 1; a <=9; a++)
{
for (int b = 1; b <= 9; b++)
{
if (b != a)
for (int c = 1; c <= 9; c++)
{
if (c != a && c != b)
for (int d = 1; d <= 9; d++)
{
if (d != a && d != b && d != c)
for (int e = 1; e <= 9; e++)
{
if (e != a && e != b && e != c && e != d)
if ((a * 10 + b) * (c * 100 + d * 10 + e) == (a * 100 + d * 10 + b) * (c * 10 + e))
sum++;
printf("(%d * 10 + %d) * (%d * 100 + %d * 10 + %d) == (%d * 100 + %d * 10 + %d) * (%d * 10 + %d)==%d\n",a,b,c,d,e,a,d,b,c,e, (a * 10 + b) * (c * 100 + d * 10 + e));//验证
}
}
}
}
}
printf("sum=%d", sum);
return 0;
}
前缀判断
//如下的代码判断 needle_start指向的串是否为haystack_start指向的串的前缀,如不是,则返回NULL(空)。
//比如:"abcd1234" 就包含了 "abc" 为前缀
#include<iostream>
using namespace std;
char* prefix(char* haystack_start, char* needle_start)
{
char* haystack = haystack_start;//母串
char* needle = needle_start;//前缀
while (*haystack && *needle) //两个指针没有越界
{
if (*(haystack++)!=*(needle++)) //填空位置
//移动指针并判断
//“++”在后,先取内容,再作移动
return NULL;//return NULL说明needle_start指向的串不是haystack_start指向的串的前缀
}
if (*needle) //needle没有越界
return NULL;//省略else
//else
//return haystack_start;
return haystack_start;
}
int main()
{
cout << prefix("abcd1234","abc") << endl;//测试
return 0;
}
//请分析代码逻辑,并推测划线处的代码,通过网页提交。
//注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
三部排序
//一般的排序有许多经典算法,如快速排序、希尔排序等。
//但实际应用时,经常会或多或少有一些特殊的要求。我们没必要套用那些经典算法,可以根据实际情况建立更好的解法。
//比如,对一个整型数组中的数字进行分类排序:
//使得负数都靠左端,正数都靠右端,0在中部。注意问题的特点是:负数区域和正数区域内并不要求有序。可以利用这个特点通过1次线性扫描就结束战斗!!
//以下的程序实现了该目标。
//其中x指向待排序的整型数组,len是数组的长度。
#include<iostream>
using namespace std;
void sort3p(int* x, int len)
{
int mod = 0;//左端点
int left = 0;//左边
int right = len - 1;//右边
while (mod <= right)
{
if (x[mod] < 0) //左移
{
int t = x[left];
x[left] = x[mod];
x[mod] = t;
left++;
mod++;
}
else if (x[mod] > 0) //右移
{
int t = x[right];
x[right] = x[mod];
x[mod] = t;
right--;
}
else //x[mod]=0
{
mod++; //填空位置
//0在中部,无需移动,指针继续前移即可
}
}
}
int main()//测试
{
int x[] = { 25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0 };
sort3p(x, 14);
for (int i = 0; i < 14; i++)
{
cout << x[i] << endl;
}return 0;
}