C++程序设计ACM题库总结

文章目录

  • C++程序设计ACM题库总结
    • 知识点总结
      • 串流
      • log
      • ceil
      • count
      • reverse
      • string的各种操作
      • sort
      • sort自定义排序方式
      • map容器
      • set容器
      • set自定义排序方法
      • bitset容器
      • C++格式化输出
      • 判断素数的方法
      • 1190 列出完数
      • 1191 12!配对
      • 1192 整数的因子数
      • 1193 浮点数的位码
      • 1194 对称素数
      • 1195 密钥加密
      • 1203 密钥解密
      • 1204 01串排序
      • 1205 按绩点排名
      • 1206 去掉双斜杠注释
      • 1207 n!的位数
      • 1208 排列对称串
      • 1209 勒让德多项式
      • 1210 立方数与连续奇数和
      • 1211 菲波那契数
      • 1212 简单四则运算
      • 1213 大数加
      • 1214 大数和
      • 1215 彼此两点最近
      • 1216 离直线最近的点
      • 1217 大数乘
      • 1218 n!中的0
      • 1219 整数模
      • 1220 N个胜利者
      • 1221 表达式个数
      • 1221 表达式个数

知识点总结

串流

    istringstream类用于执行C++风格的串流的 输入操作。ostringstream类用于执行C风格的串流的 输出 操作。strstream类同时可以支持C风格的串流的 输入输出 操作。istringstream的构造函数原形如下:istringstream::istringstream(string str);它的作用是从string对象str中读取字符,以空格为分隔符。这三个类使用时要加头文件<sstream>// 举例:
#include<sstream>
for (string s; getline(cin, s);) {    istringstream sin(s); // 从s中读取字符,以空格为分隔符。for (sin >> b; sin >> op >> c;) {   // 读到各个变量中……}
}   // 又举例:
#include<sstream>
string str="i am a boy";
istringstream is(str);  从str中读取字符,以空格为分隔符。
string s;
while(is>>s)  {  cout<<s<<endl;
}
/*
输出是:
i
am
a
boy
*/

log

c++中的log函数:引入头文件<cmath>以e为底:log(n)以10为底:log10(n)// 以m为底:log(n)/log(m)

ceil

格式: double ceil(double x); //参数为double!
作用: 返回 大于等于x 的最小整数
引入头文件<cmath>举例:
#include<cmath>
double number = 123.54;
cout<< floor(number); // 123.00
cout<< ceil(number); //124.00

count

格式:count (Iterator first, Iterator last, const T& value );
作用:返回[first,last)范围内值为value的元素个数。可用于字符串、数组、容器等。//举例:
string c1;
int cl = count(s1.begin(), s1.end(), '1');// 又举例:
有一个数组a[];a是数组的首地址
num = count(a + 1, a + 5, 0);

reverse

功能:反转在[first,last)范围内的顺序,无返回值。多用于字符串、数组、容器。
头文件是 <algorithm>

string的各种操作

要加头文件<string>

初始化

string(int n, char c); //使用 n 个字符 c 初始化
如:string str(5,'0');

substr

string substr(int pos = 0, int n = npos) const;
返回 由 pos 开始的 n 个字符 组成的字符串;若只有一个数字pos,表示从该数字到结尾。如:
string s("123456789");
cout<<s.substr(0, 5); // 输出12345
cout<<s.substr(3); // 输出 456789

string::find 返回第一次出现的位置

格式:
size_t find ( const string& str, size_t pos = 0 );
size_t find ( const char* s, size_t pos = 0 );
size_t find ( char c, size_t pos = 0 );
作用:
返回 str/s/c 在字符串中第一次出现的位置。如果没有找到,那么会返回一个特别的标记npos。(返回值可以看成是一个int型的数)如果指定了Pos,则查找只在Pos之后的位置进行。//举例:
string str ("There are two needles in this haystack.");
size_t found = str.find("needle")
if (found != string::npos)cout << int(found) << endl;// 14

string::find_first_of

格式:
size_t find_first_of ( const string& str, size_t pos = 0 );
size_t find_first_of ( const char* s, size_t pos = 0 );
size_t find_first_of ( char c, size_t pos = 0 );
作用:
在字符串中查找一个或多个字符,该一个或多个字符只需要是 str/s/c 内容的一部分即可, 并返回该内容在字符串中第一次出现的位置。
如果指定了Pos,则查找只在Pos之后的位置进行。//举例:string str ("Replace the vowels in this sentence by asterisks.");size_t found = str.find_first_of("aeiou"); while (found!=string::npos) { str[found]='*'; found = str.find_first_of("aeiou",found + 1); } cout << str << endl;
// 输出:R*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.

string::find_first_not_of

格式:
size_t find_first_not_of ( const string& str, size_t pos = 0 );
size_t find_first_not_of ( const char* s, size_t pos = 0 );
size_t find_first_not_of ( char c, size_t pos = 0 );
作用:
在字符串中查找一个或多个字符,要求该一个或多个字符不是 str/s/c 内容的一部分, 并返回该内容在字符串中第一次出现的位置。
如果指定了Pos,则查找只在Pos之后的位置进行。//例子: string str (“look for non-alphabetic characters...”); size_t found = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz "); if (found != string::npos) { cout << "str里第一个非字母的字符是" << str[found]; // -cout << "这个字符的位置:" << int(found) << endl; // 12} return 0;
}

string::find_last_of 返回最后一次出现的位置

格式:
size_t find_last_of ( const string& str, size_t pos = 0 );
size_t find_last_of ( const char* s, size_t pos = 0 );
size_t find_last_of ( char c, size_t pos = 0 );
作用:
从字符串的最后开始查找,查找一个或多个字符,该一个或多个字符只需要是str, s 或 c内容的一部分即可, 并返回该内容在字符串中最后一次出现的位置。
如果指定了Pos,则查找只在Pos之前的位置进行,之后的内容忽略。

string::find_last_not_of

格式:
size_t find_last_not_of ( const string& str, size_t pos = 0 );
size_t find_last_not_of ( const char* s, size_t pos = 0 );
size_t find_last_not_of ( char c, size_t pos = 0 );
作用:
从字符串的最后开始查找,查找一个或多个字符,该一个或多个字符b不是str, s 或 c内容的一部分, 并返回该内容在字符串中最后一次出现的位置。
如果指定了Pos,则查找只在Pos之前的位置进行,之后的内容忽略。// 例子:string str ("erase trailing white-spaces \n"); string whitespaces (" \t\f\v\n\r"); size_t found = str.find_last_not_of(whitespaces); if (found!=string::npos) str.erase(found+1); //删除found后面的内容cout << str ; //erase trailing white-spacesreturn 0;
}

【C++中string.find()函数与string::npos参考文章:https://www.cnblogs.com/zl1991/p/7262130.html】

sort

格式:
void sort (Iterator first, Iterator last);
void sort (Iterator first, Iterator last, Compare comp ); // 自定义排序方式
作用:
将 [first,last) 范围内元素按升序(从小到大)排序。如指定comp参数,元素间按照comp指定排序方式进行排序。

sort自定义排序方式

// 方法一:自定义函数(排列对称串里用到)
bool myComp(const string& s1, const string& s2) {return s1 <= s2;
}
sort(ss.begin(), ss.end(), myComp); // sort(begin, end, 自定义的函数名);
// 方法二:结构体对象
struct classComp { bool operator() (string s1, string s2) { // 先按长度再按ASCII码return s1.length() != s2.length() ? s1.length() < s2.length() : s1 <= s2;}
} myobject;
sort(ss.begin(), ss.end(), myobject); // sort(begin, end, 自定义的结构体对象名);
//方法三:运算符重载(彼此两点最近、离直线最近的点 2题里用到过)
bool operator<(const Point& a, const Point& b) { return a.x != b.x ? a.x < b.x : a.y < b.y;
}

map容器

map< key,value >1. map是一种关联容器,存储的每个对象包含两部分内容:键元素ke和值元素value。键和值类型可以不同。键元素用于唯一标识对象。用key进行访问和查找value2. map 的好处是键值自动形成了大小比较的标准 , 无论插入还是删除 , 都是内部自动维护从小到大的顺序 , 因为查找方式用的是二分法查找 , 速度比顺序查找快很多。3. map需要掌握的方法:定义:map<int,int> m;访问:m[3]=100;删除:m.erase(it); 或者 m.erase(key);查找:m.find(key) //返回指向查找对象的指针。

set容器

set<元素类型>set不允许容器中有重复的元素,multiset允许容器中有重复的元素set/multiset属于关联式容器,底层结构是用二叉树实现,所有元素都会在插入时自动从小到大被排序,因此查找速度比较快。set需要掌握的方法:定义:set<int> s;插入:s.insert(3);删除:s.erase(it) 或 s.erase(3);查找:s.find(3);   //返回指向查找对象的指针,如果没找到则返回指向end的指针:s.end()注意set 不能用[i]访问,只能用迭代器访问

set自定义排序方法

// 方法:构建结构体
struct mycomp { bool operator() (const int& a, const int& b) { // 参数类型与set元素类型要一致  return a < b;}
}; set<int,mycomp> myset; //定义:set<元素类型,结构体名> myset;
之后 myset.insert(元素) 时自动会排好序

bitset容器

 1. Bitset是一种用来存储位bit的容器。每个元素是c++中最小元素类型char型,只占用一位。元素仅包含两个可能的值:0或1 (true或false)。2. Bitset能够由整型值或由0、1构成的字符串构建,并可以转换成整型值或由0、1构成的字符串。3. 每个元素可以被单独访问。与数组非常相似。例如:一个bitset类型的mybitset,则mybitset[3]访问bitset中的第四个元素,就像访问数组元素一样。4. bitset需要掌握的方法:定义:bitset<4> mybits;   bitset<5> mybits(string("01011"));全部置1:mybits.set(pos,val)  全部置0:mybits.reset(pos,val) 访问:mybits.test(pos) mybits.set()            定义形式: bitset<N> set ( ); bitset<N> set ( size_t pos, bool val = true );作用:无参数的:将所有元素置1。pos有参数的:将位置在pos的元素置1。注意是从右往左数!注意是从右往左数!注意是从右往左数!bitset<4> mybits; cout << mybits.set() << endl; // 全部置1,1111 cout << mybits.set(2,0) << endl; // 将从右往左数第2个位置置0,1011 cout << mybits.set(2) << endl; // 将从右往左数第2个位置置1,1111 mybits.reset()定义形式: bitset<N> reset ( );bitset<N> reset ( size_t pos ); // 它只有一个参数,就是位置作用:无参数的:将所有元素置0。有参数的:将位置在pos的元素置0。注意是从右往左数!注意是从右往左数!注意是从右往左数!bitset<4> mybits (string("1111")); cout << mybits.reset(1) << endl; // 将从右往左数第1个位置置0,1101 cout << mybits.reset() << endl; //全部置0,0000 mybits.test(i)          定义形式: bool test ( size_t pos );作用:返回某位的值。位置pos的bit值为1的话返回true,否则返回false。注意是从右往左数!注意是从右往左数!注意是从右往左数!bitset<5> mybits (string("01011")); for (size_t i=0; i< mybits.size(); ++i) cout << mybits.test(i) << endl;

C++格式化输出

//方法:要加 <iomanip> 头文件整个数字保留4位:cout << setprecision(4) << 数字;或者用:cout.precision(4); cout << 数字;保留到小数点后4位,就在前面加fixed:cout << fixed << setprecision(4) << 数字;输出宽度为 10 字符,默认右对齐:cout << setw(10) << 数字;输出宽度为 10 字符,左对齐:cout << setw(10) << left << 数字;注意:fixed,setprecision,scientific只要出现一次,就对以后的数字都起作用;但setw只对它后面的指定数字起作用。如果要去掉fixed:cout.unsetf(ios::fixed);cout << 数字;举例:
#include <iostream>
#include <iomanip>   //注意要包含该头文件
using namespace std;
int main(void)
{const double value = 12.3456789;cout << setprecision(4) << value << endl; // 4精度,输出为12.35cout << setprecision(8) << value << endl; // 8精度,输出为12.345679// 加了fixed意味着是固定点方式显示,所以这里的精度指的是小数位,输出为12.3457cout << fixed << setprecision(4) << value << endl;// 只要不unsetf,fixed和setprecision的作用就一直在,依然显示12.3457cout << value << endl;// 输出宽度为 10 字符,默认右对齐,输出为:   12.3457cout << setw(10) << value << endl;// 输出宽度为 10 字符,左对齐,输出为:12.3457   12.3457cout << setw(10) << left << value << value << endl;// 去掉了fixed,所以精度恢复成整个数值的有效位数,显示为12.35cout.unsetf(ios::fixed);cout << value << endl;// 恢复成原来的样子,输出为12.3457cout.precision(6);cout << value << endl;
}

(参考文章:http://c.biancheng.net/view/275.html)

判断素数的方法

// 从 2 到 n开方 均整除判断(原因:一个合数一定含有小于它平方根的质因子。)
bool IsPrime(int N) {for (int i = 2; i <= sqrt(N); i++)if (N % i == 0) return false; // 说明是合数不是素数return true;
}

1190 列出完数

题目:

列出完数
Time Limit:1000MS  Memory Limit:32768K
Description:
自然数中,完数寥若晨星,请在从1到某个整数范围中打印出所有的完数来。 所谓“完数”是指一个数恰好等于它的所有不同因子之和。例如,6是完数,因为6=1+2+3。而24不是完数,因为24≠1+2+3+4+6+8+12=36。
Input:
输入数据中含有一些整数n(1<n<=10000)。
Output:
对于每个整数n,输出所有不大于n的完数。每个整数n的输出由n引导,跟上冒号,然后是由空格开道的一个个完数,每个n的完数列表应占独立的一行。
Sample Input:
100
5000
Sample Output:
100: 6 28
5000: 6 28 496
Source:
qianneng

核心思想:

先把所有小于 10000 的完数计算出来,放在向量中,然后对每个 n ,只需在向量中打印每个完数 , 直到 n 之内的完数的界即可。

代码:

#include<iostream>
#include<vector>
using namespace std;
int main(){vector<int> v;for (int i = 2; i < 10000; i += 2){ //构造10000之内的完数表 // 推测完数为偶数 , 故步长为 2int sum = 1;for (int j = 2; j <= i / 2; j++) // 判断每个小于 m 的整数是否能整除 mif (i % j == 0) sum += j; // 累计 m 的因子和if (sum == i)  // 比较因子和与 mv.push_back(i);}for (int n; cin >> n;){ //循环输入数据cout << n << ":";for (int j = 0; v[j] <= n; j++)cout << " " << v[j];cout << endl;}return 0;
}

1191 12!配对

题目:

12!配对
Time Limit:1000MS  Memory Limit:32768K
Description:
找出输入数据中所有两两相乘的积为12!的个数。
Input:
输入数据中含有一些整数n(1≤n<2^32)。
Output:
输出所有两两相乘的积为12!的个数。
Sample Input:
1 10000 159667200 9696 38373635
1000000 479001600 3
Sample Output:
2
Source:
qianneng

流程:

1. 建立一个向量存放输入数据
2. 在输入数据的时候 , 可以过滤那些不是 12 ! 的因子的数进行 set 集合 , 以提高查找的效率 .
3. 在输入数据还没有进集合之前先对集合元素进行配对查找 , 若找到 , 就可以只删除集合中的对应元素,若没有找到,就进集合。因为向量不擅长中间元素的删除操作 , 这可以用 set 来做 , set 的查找速度比较快 , 在这里正好需要大量的查找工作 .

代码:

#include<iostream>
#include<set>
using namespace std;
int main(){int num = 0;int f12 = 479001600;//12!multiset<int> s;for (int n; cin >> n;) { //循环输入数据if (f12 % n == 0) { //如果这个数是12!的因子//在输入数据还没进入集合前先对集合元素进行配对查找set<int>::iterator it = s.find(f12 / n);         if (it != s.end()){ //若找到对应元素,删除集合中的对应元素num++;s.erase(it);}           else{ //若没有找到对应元素,该元素进集合s.insert(n);}}}cout << num << endl;//输入数据中所有两两相乘的积为12!的个数return 0;
}

1192 整数的因子数

题目:

整数的因子数
Time Limit:2000MS  Memory Limit:32768K
Description:
找出整数的所有因子数。 一个整数n的因子数为包含它自身的所有因子的个数。例如:12的因子数为6(1,2,3,4,6,12)。
Input:
输入数据中含有一些整数n(1≤n<2^32)。
Output:
对于每个n,列出其所有因子数,每个n加上冒号单独列一行。
Sample Input:
11 22 33 24
Sample Output:
11: 2
22: 4
33: 4
24: 8
Source:
qianneng
*/

知识点:

1. 数学定理的应用:一个整数的因子数等于其每个素因子的个数加一之后的乘积
2. 判断素数最有效的方法:从2到sqrt(n)整除判断
3. map

核心思想:

1. 一个整数的因子数等于其每个素因子的个数加一之后的乘积注意:超过其平方根值的素因子最多只有一个。/*例如:12=2×2×3,2和3就是12的素因子。2有2个,3有1个,12的因子数就是(2+1)+(1+1)=5个,再看12的因子有:1、2、3、4、6,确是5个。*/2. 使用容器 map。

流程:

main():1. 构造素数表;2. 对于每个整数,遍历素数表,构造该整数的素因子表;3. 遍历该整数的素因子表,该个整数的因子数等于它的所有素因子个数加1之后的乘积;4. 输出该个整数的因子数。

代码:

// 一般方法#include<iostream>
#include<map>
using namespace std;int main()
{map<int, int> m;for (int n; cin >> n;)//输入{int num = 2;for (int i = 2; i <= n / 2; i++)if (n % i == 0) num++;m.insert(make_pair(n, num));}for (auto num : m) //输出cout << num.first << ":" << num.second << endl;return 0;
}// 改进方法
// 核心思想:一个整数的因子数等于其每个素因子的个数加一之后的乘积
#include<iostream>
#include<map>
#define MAX 6600
using namespace std;// 判断素数
// 从2到n开方均整除判断(原因:一个合数一定含有小于它平方根的质因子。)
bool IsPrime(int N) {for (int i = 2; i <= sqrt(N); i++)if (N % i == 0) return false;return true;
}int main()
{//构造2^16以内的素数表。/* 因为输入的整数n(1≤n<2^32)),而超过其平方根值的素因子最多只有一个,所以只需要到平方根就行了,超过平方根的最后再做判断*/int W[MAX]; // 素数表int Size = 0;for (int i = 2; i < (1 << 16); i++)if (IsPrime(i)) W[Size++] = i;int N;while (cin >> N){//对于每个整数,遍历素数表,构造该整数的素因子表int Tmp = N;map<int, int> Map; // 该整数的素因子表(主键存放素因子,值存放分解个数)for (int i = 0; Tmp != 1 && i < Size; ){if (Tmp % W[i] == 0) // 如果W[i]是这个整数的素因子{Map[W[i]]++;Tmp /= W[i];}elsei++;// 或者直接 Map[W[i]] = Tmp / W[i]; Tmp /= W[i]; i++; ?}// 最后除完后得到的Tmp也是一个素因子,判断Tmp是否大于2^16,如果大于2^16就加到素因子表里。if (Tmp > (1 << 16)) Map[Tmp]++;//遍历该整数的素因子表,该个整数的因子数等于它的所有素因子个数加1之后的乘积int Sum = 1;for (map<int, int>::iterator It = Map.begin(); It != Map.end(); It++)Sum *= (1 + It->second);//输出该个整数的因子数cout << N << ":" << Sum << endl;}return 0;
}

1193 浮点数的位码

题目:

浮点数的位码
Time Limit:1000MS  Memory Limit:32768K
Description:
长双精度型是C++语言内部表达能力最强的数据类型。研究其内部的位码也是饶有兴趣的。针对每个长双精度数,输出其位码。
Input:
输入数据中含有一些浮点数n(-3.4×10^4932<n<1.1×10^4932)。
Output:
对于每个n,列出其位码,每个位码8位一组,中间用逗号隔开,每5组成一行,每个位码列成两行,位码之间空出一行,见样本输出。
Sample Input:
15.6756
12345.67891023456
Sample Output:
00000000,01110000,11010111,00010010,11110010
01000001,11001111,11111010,00000010,0100000000000000,01101000,10011001,00111110,00110100
10110111,11100110,11000000,00001100,01000000Hint:
浮点内码各编译器实现不同.本题用BCB测试数据,故请用BCB提交.
Source:
qianneng

核心思想:

1. 长双精度型数的长度为 10 个字节 , 这可以从 sizeof ( long double ) 中得到。
2. 因为长双精度数是浮点数,没有移位操作,所以要将其转换成整型,转换为指针,为了对应 8 位一个单元的输出,将其转换为字符指针。
3. 输出:每次打印一个长双精度数之前确定是否是空行。(用一个m计数。一共是 10 个字节 , 所以打印一个长双精度数要循环 10 次;每个"字节"再循环 8 次;输出一个 8 位后要查看是打印逗号还是回车。(用i判断。

代码:

#include<iostream>
using namespace std;int main()
{int m = 0;for (long double d; cin >> d;){cout << (m++ ? "\n" : ""); // 每打印一个长双精度数之前确定是否空行char* p = (char*)&d; //转换为字符指针for (int i = 0; i < 10; ++i) //长双精度占10个字节,循环10次{for (int j = 7; j >= 0; --j) //每个字节存储8位无符号数,循环8次{cout << (*(p + i) >> j & 1); //判断右移j位后,最右边的一位是不是1}cout << (i % 5 == 4 ? "\n" : ","); //输出一个8位后查看是打印逗号还是回车// 如 i=0,1,2,3,5,6,7,8时打印逗号,i=4和9时打印回车}}return 0;
}

1194 对称素数

题目:

对称素数
Time Limit:1000MS  Memory Limit:32768K
Description:
统计输入的整数中有多少个对称素数。
Input:
输入数据中含有一些随机整数n(1<n<10^8)。
Output:
统计一共读入了多少个对称素数,并予以输出。
Sample Input:
15
11 313
Sample Output:
2
Source:
qianneng

核心思想:

1. 偶数位的对称数一定是合数。//如1221是合数。
2. 先建立10^7内的素数表,采用位集 bitset 筛法是一种快捷的方式。
3. 为了节省时间,通过建立素数表和对称数表,进行交集操作得到一个对称素数表。

流程:

1. 建立素数表:排除8位的数字,建10^7以内的素数表p;p里有10^7位,每一位代表该位数字是否是素数,p[i]=1 说明 i 是素数;把是2的倍数的位置 置0;把素数的倍数的位置 置0
2. 建立对称数表:先将个别 1 位数、2 位数对称素数放入位集中;再找3、5、7位的对称数置1;
3. 取交集;
4. 读入整数 , 只要该整数大于 10^7 , 则直接判断为非对称素数。如果小于 10^7 , 则通过查表可以确定 true 或 false。/*在简单的编程运行之后 , 发现 10 ^7 ( 或 10 ^8 ) 之内的对称素数总量也不过 651 个 , 因此 , 完全可以采用集合 set 来存放对称素数表 , 以达到与位集同样的性能 . 因为集合的搜索是二分查找 , 性能丝毫不输于位集 . 而且 , 在建立对称素数表过程中 , 还可以省略交集操作。
这种方法之后再写吧。
*/

代码:

#include<iostream>
#include<bitset>
using namespace std;
bitset<10000000> p, q; //全局位集 // 共有10^7个数void sieve(){ // 建一次性素数表pp.set(); // 10^7 位全置 1for (int i = 4; i < 10000000; i += 2) // 清除 2 的倍数位(置0)p.reset(i);for (int i = 3; i < 3163; i += 2) // 清除已是素数的倍数位 ??if (p.test(i))for (int j = i * i; j < p.size(); j += i * 2) {p.reset(j);}
}
void sym() {  // 建立非完全对称数表q ??q.set(2); q.set(3); q.set(5); q.set(7); q.set(11); // 先将个别 1 位数、2 位数对称素数放入位集中for (int i = 1; i <= 999; i += 2) { // 再找3、5、7位的对称数for (int j = 0, k,m; j <= 9; ++j) {k = 10 * (i >= 10 ? 10 : 1) * (i >= 100 ? 10 : 1);m = (10 * k + 1) * i + k * j + (i < 10 ? 0 : (i < 100 ? 9 * (i % 10 - i / 10) : 99 * (i % 10 - i / 100)));q.set(m);}}
}
int main(){sieve(); // 建一次性素数表sym(); // 建立非完全对称数表q &= p; // 取交集int num = 0;for (int a; cin >> a; )if (a < 10000000) num += q.test(a);cout << num << "\n";return 0;
}//其他方法
#include<iostream>
#include<string>
#include<sstream>
#include<math.h>
using namespace std;
bool isPrime(int n)
{int i;if (n == 1){return false;}if (n != 2 && n % 2 == 0)return false;for (int i = 3; i * i < n; i++){if (n % i == 0)return false;}return true;
}
int main()
{int x; int sum = 0;while (cin >> x){if (isPrime(x)){string s;stringstream ss;ss << x;ss >> s;int n = s.length(), flag = 1;for (int i = 0; i <= n / 2; i++){if (s[i] != s[n - 1 - i]){flag = 0;break;}}if (flag)sum++;}}cout << sum << endl;return 0;
}

1195 密钥加密

题目:

密钥加密
Time Limit:1000MS  Memory Limit:32768K
Description:
密钥加密是将密钥数字串值循环加到明文(需要加密的文字串)上,使得明文变形而不可阅读,变形后的文字串称为密文。
例如,密钥为4972863,明文为“the result of 3 and 2 is not 8”,则循环加密的过程及结果为:即密文为:xql"zkvyu "wl#7)hpl&5$rz"vuw$A这里的密钥加密是循环加密,并且在ASCII码值32(’ ’)到122(’z’)之间做模运算,超过了122的值便依次回跳到32,33,...等值。例如,’t’+7=116+7=123=122+1,其值超过122一个位置,因此回跳到值32。显然,密文也全部是由可见字符所组成。Input:
输入数据中含有若干组数据,每组数据由密钥和明文组成,密钥和明文均单独占一行。每组数据之间没有空行。
Output:
对于每组数据,对应输出一行密文。
Sample Input:
4972863
the result of 3 and 2 is not 8
123
Hello World
Sample Output:
xql"zkvyu "wl#7)hpl&5$rz"vuw$A
Igomq#Xqumf
Source:
qianneng

代码:

#include<iostream>
#include<string>
using namespace std;//密钥加密。Key是密钥,mw是明文,返回密文。
string Encode(string Key, string mw) {string Result; // 密文for (int i = 0; i < mw.length(); i++) {char ch = char(mw[i] + Key[i % Key.length()] - '0'); // 明文字符加上对应的密钥数字if (ch > 122) ch = ch - 91; // 如果超出范围 -122+31      Result += ch; }return Result;
}
int main() {for (string Key, mw; getline(cin, Key) && getline(cin, mw);)cout << Encode(Key, mw) << endl;return 0;
}

1203 密钥解密

题目:

密钥解密
Time Limit:1000MS  Memory Limit:32768K
Description:
密钥解密是在同一密钥加密的基础上进行解密,也可以看作是加密的反操作。解密是将密文的对应位循环减去密钥数字串值,使得密文变形显露为明文。
例如,用同一密钥”4972863”对密文:xql"zkvyu "wl#7)hpl&5$rz"vuw$A进行解密:即得到明文:the result of 3 and 2 is not 8密钥解密也是循环解密,并且在ASCII码值32(’ ’)到122(’z’)之间做模运算,小于32的值,便依次跳跃到122,121,...等值。例如,32-7其值已不足32的7个位置,它应该跳到122-6=116即’t’上。Input:
输入数据中含有若干组数据,每组数据由密钥和密文组成,密钥和密文均单独占一行。每组数据之间没有空行。
Output:
对于每个数据组,对应输出一行明文。
Sample Input:
4972863
xql"zkvyu "wl#7)hpl&5$rz"vuw$A
123
Igomq#Xqumf
Sample Output:
the result of 3 and 2 is not 8
Hello World
Source:
qianneng

代码:

#include<iostream>
#include<string>
using namespace std;
//密钥解密。Key是密钥,mw是密文,返回明文。
string Decode(const string Key, const string mw) {string Result;for (int i = 0; i < mw.length(); i++) {char ch = char(mw[i] - Key[i % Key.length()] + '0');if (ch < 32) ch = ch + 91;// 如果超出范围 -31+122Result += ch;}return Result;
}
int main() {for (string Key, mw; getline(cin, Key) && getline(cin, mw);)cout << Decode(Key, mw) << endl;return 0;
}

1204 01串排序

题目:

01串排序
Time Limit:1000MS  Memory Limit:32768K
Description:
将01串首先按长度排序,长度相同时,按1的个数多少进行排序,1的个数相同时再按ASCII码值排序。
Input:
输入数据中含有一些01串,01串的长度不大于256个字符。
Output:
重新排列01串的顺序。使得串按基本描述的方式排序。
Sample Input:
10011111
00001101
1010101
1
0
1100
Sample Output:
0
1
1100
1010101
00001101
10011111
Source:
qianneng

核心思想:

1. 容器选用:因为需要排序,比较好的办法是采用集合容器 set。考虑到集合中可能会出现相同的元素,可重集 multiset。Multiset可以单独指定比较函数。2. 排序方式:string 串大小比较的默认标准是按各字符的 ASCII 码大小,如果算法中需要改变大小比较的标准,则要自己设计比较函数。Multiset自定义比较排序方法。3. STL内置算法:count;

代码:

#include<iostream>
#include<set>
using namespace std;
struct Comp{bool operator()(const string& s1, const string& s2)const {//首先按长度排序if (s1.length() != s2.length()) return s1.length() < s2.length();//长度相同时,按1的个数多少进行排序,1的个数相同时再按ASCII码值排序。int cl = count(s1.begin(), s1.end(), '1');int c2 = count(s2.begin(), s2.end(), '1');return (cl != c2 ? cl < c2 : s1 < s2);}
};
int main(){multiset<string,Comp> me;multiset<string,Comp> ::iterator It;for (string s; cin >> s; )me.insert(s);for (It it = me.begin(); it != me.end(); ++it)cout << *it << endl;return 0;
}

1205 按绩点排名

题目:

按绩点排名
Time Limit:2000MS  Memory Limit:32768K
Description:
有一些班级的学生需要按绩点计算并排名。 每门课程的成绩只有在60分以上(含),才予以计算绩点。课程绩点的计算公式为: (课程成绩 – 50) ÷ 10 × 学分数 一个学生的总绩点为其所有课程绩点总和除以10。Input:输入数据中含有一些班级(≤20)。 每个班级的第一行数据n(≤10),a1,a2,a3,…,an,表示该班级共有n门课程,每门课程的学分分别为a1,a2,a3,…,an; 班级数据中的第二行数据为一个整数m(≤50),表示本班级有m个学生; 班级数据接下去有m行对应m个学生数据; 每行学生数据中的第一个为字串s1(s1中间没有空格),表示学生姓名,后面跟有n个整数s1,s2,s3,…,sn,表示该学生各门课程的成绩(0≤si≤100)。Output:以班级为单位输出各个学生按绩点分从大到小的排名。如果绩点分相同,则按学生名字的ASCII串值从小到大排名。 每个班级的排名输出之前应先给出一行,描述班级序号“class #:”(#表示班级序号),班级之间应空出一行。 排名时,每个学生占一行,列出名字和总绩点。学生输出宽度为10个字符,左对齐,在空出一格后列出总绩点。Sample Input:
1
3 3 4 3
3
张三   89 62 71
smith 98 50 80
王五   67 88 91Sample Output:
class 1:
王五        3.26
smith      2.34
张三        2.28
Hint:
请用BCB提交
Source:
qianneng

流程:

定义学生结构体
自定义比较函数(应用运算符重载)
存学分用vector,存学生信息用set
读数据,每次循环计算绩点并存入(存入时会使用自定义排序方式)
输出

代码:

#include<iostream>
#include<string>
#include<set>
#include<vector>
#include<algorithm>
#include<iomanip>
using namespace std;// 学生结构体
struct Student  {string s;//学生姓名double d;//学生绩点Student(string ss, double dd) : s(ss), d(dd) {} //构造函数
};//比较函数,先比较绩点,再比较姓名。
bool operator<(const Student& a1, const Student& a2)  {return(a1.d != a2.d ? a1.d > a2.d : a1.s < a2.s);
}
// ma.insert(Student(s, sum / 100)); //插入时采用自定义比较规则 int main() {int num;cin >> num;//班级数for (int i = 0; i < num; ++i) // 每个班级{int n, m;cin >> n; // 课程数 vector<int> credit(n); // 各个课程的学分 for (int j = 0; j < n; ++j)cin >> credit[j];set<Student> ma; // 学生容器cin >> m; //学生数for (int i = 0; i < m; i++) { // 每个学生string s;cin >> s; // 学生姓名double sum = 0;for (int i = 0, a; i < n && cin >> a; ++i) // 输入一门成绩累计一次绩点 if (a >= 60)sum += (a - 50) * credit[i];ma.insert(Student(s, sum / 100)); //插入时采用自定义比较规则 }cout << fixed << setprecision(2); // 保留到小数点后两位。头文件#include<iomanip>。cout << (i ? "\n" : "") << " class " << i + 1 << endl;set<Student>::iterator It;for (It it = ma.begin(); it != ma.end(); ++it)cout << left << setw(11) << it->s << it->d << endl;// 因为学生名字是左对齐 , 外加空一格 , 所以长度 11 来输出名字。头文件#include<iomanip>。}return 0;
}

1206 去掉双斜杠注释

题目:

去掉双斜杠注释
Time Limit:1000MS  Memory Limit:32768K
Description:
将C++程序代码中的双斜杠注释去掉。
Input:
输入数据中含有一些符合C++语法的代码行。需要说明的是,为了方便编程,规定双斜杠注释内容不含有双引号。
Output:
输出不含有双斜杠注释的C++代码,原语句行格式不变,行尾也不应有空格。Sample Input:
//======================
// simplest program
//======================
#include<iostream>
using namespace std;
//----------------------
int main(){cout<<”hello world!\n”;
}//---------------------Sample Output:
#include<iostream>
using namespace std;
int main(){cout<<”hello world!\n”;
}
Source:
qianneng

知识点:

string里的:find_first_not_offind_last_offind_last_not_ofstring::npossubstr

流程:

每次循环输出一行,输出一行时有以下几种情况:1        空行
2       //======================
3.1     int n = s.find ("//");
3.2     }  //---------------------判断步骤:1 空行 // 不输出2 非空行,打头的是双斜杠:// 不输出3 非空行,打头的不是双斜杠,找到双引号的位置(没有双引号位置就是0):3.1 双引号后没有双斜杠 // 原句输出3.2 双引号后有双斜杠 // 从双斜杠起倒着找非空字符,然后将从头开始到该非空字符的字串输出

代码:

#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{vector<string> s;for (string str; getline(cin, str);)s.push_back(str);for (int i = 0; i < s.size(); i++) //逐行输出{int p = s[i].find_first_not_of(' '); // p是第一个非空字符//1 在行中从头开始找第 1 个非空字符,如果找不到,则说明那是空行,应予以保留。if (p == string::npos){cout << endl;continue;}//2 判断非空字符打头的是否双斜杠,若是,说明为整行注释,应予以去掉。if (s[i].substr(p, 2) == "//"){continue;}//3 从行尾开始往前找双引号,若找到,就从p开始进行第4步p = s[i].find_last_of('"');if (p == string::npos) // 行中无双引号,就从0开始进行第4步{p = 0;}//3.1 从p开始找双斜杠,若没有找到双斜杠,则原句原样输出p = s[i].find("//", p);if (p == string::npos){cout << s[i] << "\n";}//3.2 若找到双斜杠,则为了去掉双斜杠之前多余的空格,须从双斜杠起倒着找非空字符,然后将从头开始到该非空字符的字串输出else {p = s[i].find_last_not_of(' ', p - 1);cout << s[i].substr(0, p + 1) << "\n";}    }return 0;
}

1207 n!的位数

题目:

n!的位数
Time Limit:2000MS  Memory Limit:65536K
Description:
针对每个非负整数n,计算其n!的位数。
Input:
输入数据中含有一些整数n(0≤n<10^7)。
Output:
根据每个整数n,输出其n!的位数,每个数占独立一行。
Sample Input:
5
6
Sample Output:
3
3
Source:
qianneng

核心思想:

n!的位数 = log1 + log2 + …… + logn (如果有小数则向上取整,应用ceil函数)

代码:

#include<iostream>
#include<cmath>
using namespace std;
int main()
{int n;while (cin >> n) {double sum = 0;for (int i = 1; i <= n; i++){sum += log10(i * 1.0); }cout << ceil(sum);}return 0;
}

1208 排列对称串

题目:

排列对称串
Time Limit:1000MS  Memory Limit:32768K
Description:
很多字串,有些是对称的,有些是不对称的,请将那些对称的字串按从小到大的顺序输出。字串先以长度论大小,如果长度相同,再以ASCII码值为大小标准。
Input:
输入数据中含有一些字串(1≤串长≤256)。
Output:
根据每个字串,输出对称的那些串,并且要求按从小到大的顺序输出。
Sample Input:
123321
123454321
123
321
sdfsdfd
121212
\\dd\\
Sample Output:
123321
\\dd\\
123454321
Source:
qianneng

代码:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;// 判断对称
bool isSym(const string& s) {for (int i = 0; i < s.length() / 2; ++i)if (s[i] != s[s.length() - 1 - i])  return false;return true;
}// 自定义比较函数
bool myComp(const string& s1, const string& s2) { // 先按长度再按ASCII码return s1.length() != s2.length() ? s1.length() < s2.length() : s1 <= s2;
} int main() {vector<string> ss;for (string s; getline(cin, s);) {if (isSym(s))   ss.push_back(s); // 如果是对称串就加入容器sort(ss.begin(), ss.end(), myComp);}for (int i = 0; i < ss.size(); i++)cout << ss[i] << endl;return 0;
}

1209 勒让德多项式

题目:

勒让德多项式
Time Limit:1000MS  Memory Limit:32768K
Description:
数学poly函数的展开式也称为关于x的n阶勒让德多项式,它的递推公式为:poly_n(x)=1 ,n=0;x ,n=1;( (2n-1) * x * poly_n-1(x) - (n-1) * poly_n-2(x) ) / n ,n>1 给定x,请你计算n阶勒让德多项式的值。
Input:
输入数据中含有一些浮点数x(0<x<1)。
Output:对于每个x,分别计算2阶、3阶、4阶、5阶、6阶的勒让德多项式的值,其每个值的精度为6位小数。输出时,先列出x的值,保留3位小数精度,然后每输出一个阶值之前,都空出2格,由此一字排开,形成一张多项式表,见样本输出格式.其中标题行上第一个x对准小数点后第一位,后面的每个字母p对准下列的小数点位置。
Sample Input:
0.2 0.3 0.35
Sample Output:x      p2(x)      p3(x)      p4(x)      p5(x)      p6(x)
0.200  -0.440000  -0.280000   0.232000   0.307520  -0.080576
0.300  -0.365000  -0.382500   0.072938   0.345386   0.129181
0.350  -0.316250  -0.417812  -0.018723   0.322455   0.222511
Hint:
请用BCB编译器提交
Source:
qianneng

流程:

每行输出格式:
2个空格 -> x值(保留到小数点后3位) -> p2(x)的值 -> p3(x)的值 -> p4(x)的值 -> p5(x)的值 -> p6(x)的值 (p_n(x)保留6位小数,右对齐占11位,不足的地方用空格补齐)

代码:

#include <iostream>
#include<iomanip>
using namespace std;
int main()
{int i = 0;cout << fixed;for (double x; cin >> x;) {if (i == 0) {cout << "  x      p2(x)      p3(x)      p4(x)      p5(x)      p6(x)" << endl;i = 1;}cout << setprecision(3) << x ;double as = 1; // poly_n-1(x)double at = x; // poly_n-2(x)for (int n = 2; n <= 6; n++) {double au = ((2 * n - 1) * x * at - (n - 1) * as) / n;as = at;at = au;cout << setprecision(6) << setw(11) << au;}cout << endl;}return 0;
}

1210 立方数与连续奇数和

题目:

立方数与连续奇数和
Time Limit:5000MS  Memory Limit:32768K
Description:
一个整数的立方数,可以表示为整数项连续奇数的和,例如: 3^3 = 7+9+11, 4^3 = 13+15+17+19.
针对每个正整数n,输出表示其立方数的连续奇数和。
Input:
输入数据中含有一些整数n(1≤n≤100)。
Output:
根据每个整数n,输出其值等于n^3的n项连续奇数和,格式见样本输出,每个表达式输出完成后应回车。
Sample Input:
3 4 8
Sample Output:
3^3=7+9+11
4^3=13+15+17+19
8^3=57+59+61+63+65+67+69+71
Source:
qianneng

核心思想:

连续奇数的首项 begin 为 :begin = 2*m + 1 = n * n - n +1 = x * x - x + 1
末项为 :begin +2*x -1
步长为 2.

代码:

#include <iostream>
using namespace std;
int main()
{for (int x; cin >> x;) {int begin = x * x - x + 1;cout << x << "^3=" << begin;for (int i = begin + 2; i <= begin + 2 * x - 1; i += 2)cout << "+" << i;cout << endl;}return 0;
}

1211 菲波那契数

题目:

菲波那契数
Time Limit:1000MS  Memory Limit:32768K
Description:
已知菲波那契数的定义: f(0) = 0 f(1) = 1 f(n) = f(n-1) + f(n-2) n>1,整数
根据输入数据中的n,输出第n项菲波那契数。Input:
输入数据中含有一些整数n(0≤n≤46)。
Output:
根据每个整数n,输出其第n项菲波那契数,每个数占独立一行。
Sample Input:
5
6
7
8
9
40
Sample Output:
5
8
13
21
34
102334155
Source:
qianneng

代码:

// 高效方法
// 一
#include<iostream>
using namespace std;
int main() {for(int n;cin>>n;) {int a=0,b=1,c;for(int i=2;i<=n;i++)c=a+b,a=b,b=c;cout<<c<<"\n";}
}
// 二
#include<iostream>
using namespace std;
int main() {int a[47] = { 0,1 };for (int i = 2; i < 47; ++i) // 预存实验结果a[i] = a[i - 1] + a[i - 2];for (int n; cin >> n;)cout << a[n] << "\n";
}// 递归方法
#include<iostream>
using namespace std;
int fob(int n) {if (n == 0) return 0;if (n == 1) return 1;else return fob(n - 1) + fob(n - 2);
}
int main() {for (int n; cin >> n;)cout << fob(n) << "\n";
}

1212 简单四则运算

题目:

简单四则运算
Time Limit:1000MS  Memory Limit:32768K
Description:
给定一些没有括号的四则运算表达式,求其结果。
Input:
输入数据中含有一些表达式(数量≤1000,长度按含有的运算计,运算符≤30),表达式的运算符只含有加、减、乘、除。表达式中每个数的精度范围在double型内,表达式中没有任何其他运算符,没有括号。
Output:
对每个表达式,计算其结果。按科学计数法输出,精度按6位小数,每个结果应占独立一行。如果表达式发生除0的情况,则对该表达式直接输出“DivByZero”。
Sample Input:
3+5.0
6-2*7
6-2/0
3+5*6+1
3+5+1*7
1+2-3*4+5/6-4*3*2*1*1+2+3+4+5
Sample Output:
8.000000e+00
-8.000000e+00
DivByZero
3.400000e+01
1.500000e+01
-1.816667e+01
Hint:
请用BCB编译器提交
Source:
qianneng

核心思想:

将循环每次处理的状态看作是 a + b ☆ c,根据每次读入的 ☆ 进行相应操作。

流程:

    可以将循环每次处理的状态看作是 , 已有 a 、 + 、 b , 而观察将要读入的☆和 c , 即每次a + b ☆ c // 不忙做 + 操作于是 , a 的初值应为 0 , 表达式最先读入的是 b , 然后不断处理☆和 c . 其中☆可能是加、减、乘、除操作符 , 对于☆和 c 将做如下处理:☆为 + : 则先做前面的 + , 即 a = a + b , b = c ; 继续新一轮读入☆ , 和 c 循环 .☆为 - : 则先做前面的 + , " - " 相当于 + 负数 , 即 a = a + b , b = - c ; 继续新一轮读入☆ , 和 c 循环 .☆为 × : 则先做后面的 * , 即 b = b * c ; 继续新一轮读入☆ , 和 c 循环 .☆为 / : 当 c ! = 0 时 , 则先做后面的 / , 即做 b = b / c ; 继续新一轮读入☆ , 和 c 循环 , 而
当 c = 0 时 , 则直接输出 DivByZero 并中断本次表达式计算循环 .

代码:

#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main() {    for (string s; getline(cin, s) && s != "";) {istringstream sin(s);char op;double a = 0, b, c;for (sin >> b; sin >> op >> c;) {switch (op){case'-':c = -c;case'+':a += b; b = c; break;case'*':b *= c; break;case'/':if (c == 0) {cout << "DivByZero" << endl;goto A;}else b /= c;}         }cout << scientific << a + b << endl;A:;}    return 0;
}

1213 大数加

题目:

大数加
Time Limit:1000MS  Memory Limit:32768K
Description:
给定一些大数,请计算其和。
Input:
输入数据中含有一些数据组(数量≤100),每组数据由一个整数n(n≤100)领衔,后跟n个大整数(0≤大数,大数位数≤200),若n=0则表示输入结束。
Output:
输出每组数据所计算的大数和,每个结果单独占一行。
Sample Input:
5
123456789
6287999980
5645645654654
5
79
0
Sample Output:
5652057111507
Source:
qianneng

核心思想:

1. 用字符串string表示大数。因为大数200位长,无法用计算机内部数据类型表示。2. 大数求和的方法:    (1)因为输入的数字串是从高位到低位排列的,两个大数只有高位是对齐的,低位并没有对齐。知道了这个原则,就可以将两个大数都逆转一下,然后进行反向相加处理。例如 , 对 123+56789 进行倒序相加 :3 2 1 0 0 0 0+ 9 8 7 6 5 0 0———————————————————2 1 9 6 5 0 0   //将此结果翻转得“0056912”,去掉前面的0,即是结果(2)如何进行相加呢?计算每位的和,本位是对于10的余数,进位是商。

流程:

每次循环,调用add函数,将新来的大数s加在已有的大数a上add():a的每一位a[ai]与s的每一位s[si]相加,再加上进位,得到的和,除以10取余保留在本位,除以10取整进到更高位。(在下面代码的add里:因为a本来就是反转过来的,低位在前,所以从0开始。没有把参数 s 的顺序颠倒过来,而是一边从左加起,一边却从右加起,因为当 s 被逐位加完后,还要考虑到此时是否仍有进位,以便再继续加下去。)/*
注意:
考虑到一定不能让运算溢出 , 被加数的位数应该取最大大数的位数 , 再加上可能进行的操作数量的对数的上限。例如 , 最大位数为 200 位的大数 , 要做 10000 多次运算 , 则可能会达到 205 位数 .
*/

代码:

#include <iostream>
using namespace std;
void add(string &a,const string &s) // 反向相加
{int temp=0; // 进位for(int ai=0,si=s.length()-1; si>=0 || temp; ++ai,--si){temp+=a[ai]-'0'+(si>=0?s[si]-'0':0);a[ai]=temp%10+'0'; // 本位temp=temp/10; // 进位}
}
int main()
{const int bitnum=205;for(int num;cin>>num && num;){string a(bitnum,'0');for(string s;num--&&cin>>s;)add(a,s); // 反向相加reverse(a.begin(),a.end()); // 结果翻转cout<<a.substr(a.find_first_not_of('0'))<<"\n";}return 0;
}

1214 大数和

题目:

大数和
Time Limit:1000MS  Memory Limit:32768K
Description:
给定一些大数,请计算其和。
Input:
输入数据中含有一些数据组(数量≤100),每组数据由一个整数n(n≤100)领衔,后跟n个大数(大数位数≤200),若n=0则表示输入结束。
Output:
输出每组数据所计算的大数和,每个结果单独占一行。
Sample Input:
2
123123123123123123123123123123123
-2
2
43242342342342
-1234567654321
0
Sample Output:
123123123123123123123123123123121
42007774688021
Source:
qianneng

核心思想:

本题与上题的差异在于本题允许负数。思路:将负数像二进制补码的方式那样取补,再做加法。

流程:

main():1. 读入大数:如果发现带有 " - " 号 , 先删除之。另外,由于补码的加法操作会涉及高位的 9 , 与最大位数很有关系 , 所以每个正数负数都应扩充到最大位。然后取补comple()。2. 正负数准备好后进行加的操作。add()3. 最后打印结果:先判断其正负性确定是否输出“-”,a[0]为9就说明最后结果是负数的补,因为大数位数不超过200,这里设置的bitnum = 205,最高位是9,那么肯定是负数的补码。然后去掉前导 0 ,打印输出. 另外,还要考虑到如果一个大数等于 0 , 则去 0 操作将导致打印一个空串 , 这时应特别地打印一个 0 .add():a的每一位a[ai]与s的每一位s[si]相加,再加上进位 -> 得到的和 -> 除以10取余保留在本位,除以10取整进位到更高位。comple():每一位都用 9 去减;然后个位数再加 1,( 在最低位而不是在最高位 )。如果该位为 9 说明加 1 之后有进位,继续循环把它再高一位加 1,如果不是 9 说明加 1 之后不会进位,退出循环,加1操作结束。/*取补例如,最大为 5 位数的 -123 取补后得到 :99877在打印的时候,如果发现最高位是 9,则应先取补,取补之后负号相反。上面的数取补后又变回原来的值 :-00123再去掉前面 0 就是正确的结果了。这种方法的缺点是先要对负数取补,然后再做加法。*//*另一种思路:把大数的第 1 位拿来作符号位,通过第 1 位的情况来决定到底是做加法还是做减法。这种思路的缺点是 ,每次做减法时,先要判断两个数的大小,然后较大数的符号决定运算结果的符号。若较小数减去较大数,则会导致溢出。*/

代码:

#include <iostream>
using namespace std;
void comple(string& s) // 对一个十进制大数取补
{for (int i = 0; i < s.length(); ++i) s[i] = '9' - s[i] + '0'; // 每一位都用 9 去减for (int i = s.length() - 1; i >= 0; i--) // 最低位加 1if (s[i] == '9') s[i] = '0';else { s[i]++; break;}
}
void add(string& a, const string& s)
{int temp = 0;for (int ai = 0, si = s.length() - 1; si >= 0 || temp > 0; ++ai, --si){temp += a[ai] - '0' + (si >= 0 ? s[si] - '0' : 0);a[ai] = temp % 10 + '0';temp = temp / 10;}
}
int main()
{const int bitnum = 205;for (int num; cin >> num && num;){string a(bitnum, '0'); // 结果for (string s; num-- && cin >> s;){if (s[0] == '-') // 如果是负数{s = s.substr(1);s = string(bitnum - s.length(), '0') + s;comple(s);}else // 如果是正数s = string(bitnum - s.length(), '0') + s;add(a, s); // 相加}// 打印结果reverse(a.begin(), a.end());if (a[0] == '9'){comple(a);cout << "-";}int pos = a.find_first_not_of('0');if (pos == string::npos)cout << "0\n";elsecout << a.substr(pos) << "\n";}return 0;
}

1215 彼此两点最近

题目:

彼此两点最近
Time Limit:1000MS  Memory Limit:32768K
Description:
给定一些平面上的点,求出彼此距离最近的两点。
Input:
输入数据中含有一些数据组(数量≤100),每组数据由一个整数n(2≤n≤102)领衔,后跟n个平面坐标点x、y(-10000≤整数x,y≤10000)。若n=0则表示输入结束。
Output:
每组数据都有彼此距离最短的坐标点,输出所有彼此距离最短的两点x和y坐标,坐标应以x的大小和y的大小依次输出,用括号将其括起来,坐标点之间空一格,若有多对最短距离点,则换行输出,坐标点小的在前,大的在后。每组数据的结果之间空一行。
Sample Input:
4
1 2
0 0
3 6
7 2
3
1 3
3 1
0 0
11
1 2
2 3
3 5
7 5
9 6
9 7
10 8
1 9
9 1
10 11
10 12
0
Sample Output:
(0,0) (1,2)(1,3) (3,1)(9,6) (9,7)
(10,11) (10,12)
Source:
qianneng

核心思想:

1. 点的设计:
struct Point{  int a,b;Point(int x=0,int y=0):a(x),b(y){ }//构造函数,与结构体名字必须完全相同,用于对结构体类型变量初始化
}
构造函数初始化示例:Point p1;p1=Point(3,5);2. 两点之间距离计算表示方式:
int dis(const Point& p1, const Point& p2){ return(p1.a-p2.a)*(p1.a-p2.a)+(p1.b-p2.b)*(p1.b-p2.b);// 因为并不要求两点之间的精确距离,而只要求比较距离的长短,因此计算距离没有必要做开平方操作。
}3. sort自定义排序方式
bool operator<(const Point& a, const Point& b) { return a.x != b.x ? a.x < b.x : a.y < b.y;
}

流程:

main():遍历每一对点计算其距离,在比较中,如果两点的距离比原来的最短距离更短,则更新最短距离,将该两点的资料放入结果中;如果两点的距离等于原来最短的距离,则将该两点增加到结果容器中,如果两点距离大于原来最短距离,则放弃之。最后输出: 注意,结果r中的数据的意义并不是坐标点,而是最短距离的两个点在坐标点容器 p 中的序号。r[i].x是i,r[i].y是j。要输出p[i].x,p[i].y,和p[j].x,p[j].y。

代码:

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Point {Point(int dx = 0, int dy = 0) : x(dx), y(dy) { } int x, y;
};
bool operator<(const Point& a, const Point& b) { // 自定义排序方式return a.x != b.x ? a.x < b.x : a.y < b.y;
}
int dis(const Point& a, const Point& b) {return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
int main() {for (int N; cin >> N && N; ) {vector<Point> p(N), r; // 数组p存放点,r存放结果(两个点在容器 p 中的序号)for (int i = 0; i < N; ++i)cin >> p[i].x >> p[i].y;sort(p.begin(), p.end()); // 按自定义排序方式排序,让点呈大小排列int m = 1 << 30;for (int i = 0; i < N - 1; ++i) // 遍历每一对点p[i], p[j]for (int j = i + 1; j < N; ++j) {int k = dis(p[i], p[j]);if (k == m)r.push_back(Point(i, j));else if (k < m) {r.clear();r.push_back(Point(i, j));m = k;}          }for (int i = 0; i < r.size(); ++i)cout << "(" << p[r[i].x].x << "," << p[r[i].x].y << ") "<< "(" << p[r[i].y].x << "," << p[r[i].y].y << ")\n";}return 0;
}

1216 离直线最近的点

题目:

离直线最近的点
Time Limit:1000MS  Memory Limit:32768K
Description:
给定一根直线和一些平面上的点,求出到直线距离最近的点。
Input:
输入数据中含有一些数据组(数量≤100),每一组数据的第一行为一个整数n(1≤n≤100),表示本组数据中将有n个坐标点,若n为0,表示输入结束。第二行为四个整数(依次为x1,y1,x2,y2),表示确定一根直线的两个坐标点,紧接着有n对整数x,y(-10000≤x,y≤10000),表示n个坐标点。
Output:
每组数据中都有距直线最短的坐标点,输出其x和y坐标,若满足条件的点不止一个,则换行继续输出,每组数据之间应空一行。
Sample Input:
4
1 2 3 4
3 8
10 10
7 2
900 1
0
Sample Output:
10 10
Source:
qianneng

流程:

main():输入直线,每输入一个点,计算其到直线的距离,在比较中,如果比原来的最短距离更短,则更新最短距离,将该点的资料放入结果中;如果等于原来最短的距离,则将该点增加到结果容器中,如果大于原来最短距离,则放弃之。最后输出所有点,保证输出从小到大

代码:

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Point
{Point(int dx = 0, int dy = 0) : x(dx), y(dy) { } int x, y;
};
bool operator<(const Point& a, const Point& b)
{return a.x != b.x ? a.x < b.x : a.y < b.y;
}
int main()
{for (int n, w = 0; cin >> n && n;){int x1, y1, x2, y2, m = 1 << 30;  // 距离初值故意设得很大 cin >> x1 >> y1 >> x2 >> y2;int A = y2 - y1, B = x1 - x2, C = y1 * x2 - x1 * y2;vector<Point>   r;  // 结果向量 for (int i = 1, x, y, k; i <= n && cin >> x >> y; ++i){if ((k = x * A + y * B + C) < 0)k = -k;  // 取整型绝对值 if (k == m)r.push_back(Point(x, y));else if (k < m) {r.clear();r.push_back(Point(x, y));m = k;}}sort(r.begin(), r.end()); // 保证输出从小到大 , 注意使用默认比较函数 cout << (w++ ? " \n " : "");for (int i = 0; i < r.size(); ++i)cout << r[i].x << " " << r[i].y << " \n ";}return 0;
}

1217 大数乘

题目:

大数乘
Time Limit:5000MS  Memory Limit:32768K
Description:
给定一些大数,请计算其积。
Input:
输入数据中含有一些整数对(对数≤1000),若某对整数(整数位数≤200)的值为0 0,则表示输入结束。
Output:
每对整数对应一个乘法计算结果,输出该结果,每个结果输出完后应回车。
Sample Input:
2 3
12 34
0 0
Sample Output:
6
408
Source:
qianneng

知识点:

1. 大数乘法方法
2. stringstring(int n, char c); //使用n个字符c初始化string substr(int pos = 0, int n = npos) const; //返回由pos开始的n个字符组成的字符串;只有一个数字pos,表示从该数字到结尾。size_t find_first_not_of ( char c, size_t pos = 0 ); // 在字符串中查找一个字符,并返回该内容在字符串中第一次出现的位置。3. reverse函数功能:反转在[first,last)范围内的顺序(包括first指向的元素,不包括last指向的元素),reverse函数无返回值。多用于字符串、数组、容器。头文件是#include<algorithm>

核心思想:

multi():1. 变量存储:因为大数可能大到 200 位,可以将大数值放在 string 变量中,以两个 string 变量为参数来调用大数乘法函数,返回乘法的结果也是 string 变量。2. 符号处理:在做乘法运算时先将负号去掉。结果的正负性可以通过判断两个数的正负性来解决。3. 乘法运算:为了方便乘法运算,可以先将两个大数的顺序都倒过来,然后都从下标 0 开始进行逐位相乘,做完乘法后,再倒回去。

流程:

1. 处理符号:去掉两个大数的负号,计算结果的正负。
2. 将结果串取到最大可能的长度,即两个大数的长度和。
3. 做乘法运算:两重循环,它先按乘数的位进行循环,然后再按被乘数的位进行循环,逐位相乘,注意保留进位。相乘与赋值时,要留意字符与数字的转换。
4. 逆转顺序,若前面有多余的 0,则再去掉前面多余的 0。/*
注意:
该代码的局限性在于,大数的长度受到 string 长度的限制,所以最多能做千位级的运算 , 若上万位的大数 , 就要用其他容器了。
*/

代码:

#include <iostream>
using namespace std;
string multi(const string &a,const string &b)
{if(a=="0"||b=="0")return "0";string aa(a[0]=='-'? a.substr(1):a);string bb(b[0]=='-'? b.substr(1):b);string sign=((a[0]=='-')+(b[0]=='-')==1?"-":"");string s(aa.length() + bb.length(),'0');reverse(aa.begin(),aa.end());reverse(bb.begin(),bb.end());// 乘法运算!乘法运算!乘法运算!for(int j=0;j<bb.length();++j) // 先按乘数的位进行循环{if(bb[j]=='0')continue;int temp=0;for(int i=0;i<aa.length();++i) // 再按被乘数的位进行循环{temp=temp+(aa[i]-'0')*(bb[j]-'0')+(s[j+i]-'0'); // 逐位相乘s[j+i]=temp%10+'0'; // 保留进位temp=temp/10;}s[aa.length()+j]+=temp;}reverse(s.begin(),s.end());return sign+s.substr(s.find_first_not_of('0'));
}int main()
{for(string a,b;cin>>a>>b&&(a!="0"||b!="0");)cout<<multi(a,b)<<"\n";return 0;
}

1218 n!中的0

题目:

n!中的0
Time Limit:1000MS  Memory Limit:32768K
Description:
贝贝很想搞清n!中到底有几个0,但是计算n!已经很不容易,很多很多位啊,算得头都晕了,再开始数0的个数,怎么也数不清了,其实这件事情让计算机做,应该是比较容易做的,请你帮助贝贝解决这个难题吧。
Input:
输入数据中包含一些整数,每个整数不大于1000。
Output:
输出每个整数的阶乘中0的个数,每个结果都回车。
Sample Input:
3
8
9
10
Sample Output:
0
2
1
2
Source:
qianneng

核心思想:

1. 大数1000!有2568位,无法用计算机内部数据类型直接表示。方法是用数组一位一位存放,用数组 a 存放阶乘值,数组zeros存放 每个n!的0的个数(下标是n)。2. 采用迭代:已知(n-1)!,乘以n得到n!3. 乘法方法

代码流程:

proc()函数构建zeros表:for(n 从 2 到 1000):先计算尾部 0 的个数 beg , 因为 0 值可以免于计算 ; 再计算 n ! 的位数 e , 它是在已知 ( n -1 ) ! 的位数前提下进行计算的 ; (为什么是double?)然后做 n ! 的计算;最后调用 count 算法计算 n ! 中的 0 的个数 , 【等到下次循环,数组a存储的 n ! 的值就被 ( n +1 ) ! 所代替而不复存在了,因此在循环中及时计算求值是要点。】  输入数字n,输出zeros[n],结束。/*
注意:1. a数组保存着的数是反着放的。2. 做 n! 的计算那里,就相当于平时的整数乘法,被乘数是n,乘数是a。乘数末尾的一串0可免于参加运算,被乘数n与乘数的每一位数a[j]相乘,本位=(低位的进位+现在的乘积)%10,进位到an,an /= 10变为更高一位的进位。???
*/

源代码:

#include <iostream>
#include<cmath>
using namespace std;
const int Factor = 1000;
int zeros[Factor], a[2568] = { 1 }; // 1000!有2568位
void proc() {double bitNum = 1.0;for (int n = 2, beg = 0, e = 0; n <= Factor; ++n) {while (a[beg] == 0) {beg++; // 累计尾部0的个数}e = bitNum += log10(n * 1.0); // n!的位数for (int j = beg, an = 0; j < e; j++, an /= 10) { // 做 n! 的计算a[j] = (an += n * a[j]) % 10;}zeros[n] = count(a + beg, a + e, 0) + beg; // 计算 n ! 中的 0 的个数}
}
int main() {proc();int n;while (cin >> n) {cout << zeros[n] << endl;}return 0;
}

1219 整数模

题目:

整数模
Time Limit:1000MS  Memory Limit:32768K
Description:
a除以m的余数称为a对于m的模。求a^p对于m的模。
Input:
输入数据中含有一些数据组,每个数据组占一行,包括a、p、m(0<a,p<2^32,1≤m<2^16)三个整数,若三个数都为0,则表示输入结束。
Output:
针对每组数据,输出a的p次幂对于m的模,每个结果占一行。
Sample Input:
3 18132 17
0 0 0
Sample Output:
13
Source:
qianneng

核心思想:

利用数学定理:1. (a*b)%m=[(a%m)*(b%m)]% m    当p为奇数时,a^p%m = [(a^(p-1)%m) * (a%m)]%m当p为偶数时,a^p%m = [ (a^(p/2)%m) * (a^(p/2)%m) ]%m2. a^p %m= [(a%m)^p]%m

代码流程:

module函数用来求模:如果P=0,直接返回1;如果p是奇数,返回[module(a,p-1,m) * (a%m)] % m如果p是偶数,返回[module(a,p/2,m) * module(a,p/2,m)] % m
输入a、p、m,用module(a % m, p, m)求模并输出。

源代码:

#include <iostream>
using namespace std;
int module(unsigned a, unsigned p, int m) {if (p == 0) return 1;if (p % 2)  return a % m * module(a, p - 1, m) % m;a = module(a, p / 2, m);return a * a % m;
}
int main() {unsigned a, p, m;while (cin >> a >> p >> m && a != 0 && p != 0 && m != 0) {cout << module(a % m, p, m) << endl;}return 0;
}

1220 N个胜利者

题目:

N个胜利者
Time Limit:2000MS  Memory Limit:32768K
Description:
n个小孩围成一圈做游戏,游戏将决出若干个胜利者。 假定一个数m,从第1个小孩起,顺时针数数,每数到第m个小孩时,该小孩离开。接着又从下一个小孩开始数数,数到第m个小孩时,该小孩也离开,如此不断反复进行,最后剩下的k个小孩便是胜利者。对于一定的n、m、k,究竟胜利者是哪些呢?
Input:
输入数据有一些数据组,每组数据含有整数n、m、k(1≤ n, m, k≤50)),分别表示小孩数,游戏中每次数数的个数和最后剩下的k个胜利者。
Output:
对于每组数据,按从小到大的顺序输出一列获胜小孩的位置。每组获胜序列之间应回车。
Sample Input:
10 3 3
Sample Output:
4 5 10
Source:
qianneng

核心思想:

1. 一直数m个然后删除,重复操作,直到剩下w个
2. 这里的环链表用数组存,数组里每个元素是个结构体,数组最后一个元素指向第一个元素;
3. 链表的删除操作(要用两个指针)

流程:

首先定义一个小孩结构体Boy,里面有小孩的编号和指向下一个小孩的指针。1. 输入小孩数、计数间隔、获胜者数量;2. 创建环链表:按小孩数new一个Boy类型的数组。再进行初始化,给每个小孩编号,让每个小孩的指针指向下一个小孩。【这里做环结构的时候巧用%,让第i-1个孩子指向第i个孩子很好做,但是如何让最后一个孩子(下标n-1)指向第1个孩子(下标0)呢?就是当i=n的时候,利用i%n=0,当然前面i不大于n的时候,i%n依然是i】;3. Boy* pivot指向前一个小孩,Boy* pCurrent指向当前小孩,从链表开始位置第0个开始,也就是pCurrent先指向第0个;4. 循环执行以下步骤,直到达到获胜者数量:数m个小孩:pCurrent 和 pivot向前移 m 个(也就是pivot = pCurrent,pCurrent = pCurrent->next);小孩离队:删除pCurrent(也就是pivot->next = pCurrent->next,pCurrent = pivot);5. 输出获胜者:vector数组wins存小孩的编号;用一个指针p遍历,从pCurrent开始,p逐渐往后移,直到又遇到pCurrent为止;sort(wins.begin(), wins.end());遍历输出wins;

代码:

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;struct Boy {int code;   // 小孩编号Boy* next;   // 指向下一个小孩
};class BoyRing {Boy* pBegin, * pivot, * pCurrent; // 小孩结构指针,前驱指针,当前小孩指针
public:BoyRing(int n);          // 构造函数void countBy(int m); // 数m个小孩int getNum() const;     // 返回当前小孩编号void disengage();        // 小孩离队void printALL()const;    // 输出所有小孩~BoyRing();                // 析构函数
};class Jose {int n, m, s, w; // 小孩数,计数间隔,开始位置,获胜者
public:Jose(int boys, int interval, int begin = 1, int wins = 1); //构造函数void getWinner() const; //求获胜者
};int main() {int n, m, k;while (cin >> n >> m >> k) { // 小孩数,计数间隔,获胜者Jose(n, m, 1, k).getWinner();}return 0;
}// 构造函数
Jose::Jose(int boys, int interval, int begin, int wins):n(boys), m(interval), s(begin), w(wins) {// 小孩校验,开始位置校验,计数间隔校验
}// 求获胜者
void Jose::getWinner()const { BoyRing x(n);     //创建环链表x.countBy(s - 1);    //转到链表开始位置for (int i = 1, numinLine = 0; i < n - w + 1; ++i) { // 循环执行以下步骤,直到达到获胜者数量x.countBy(m);    //数m个小孩x.disengage();   //小孩离队}x.printALL();        //输出获胜者
}// 构造函数
BoyRing::BoyRing(int n) { if (n < 2) throw exception();  pBegin = new Boy[n]; // 按小孩数申请空间for (int i = 1; i <= n; i++) { // 初始化为环结构,小孩编号pBegin[i - 1].code = i;pBegin[i - 1].next = &pBegin[i % n];}pivot = pCurrent = &pBegin[n - 1]; // 指针赋初值
}// 数m个小孩
void BoyRing::countBy(int m) { for (int i = 1; i <= m; ++i) {pivot = pCurrent;pCurrent = pCurrent->next;}
}// 返回当前小孩编号
int BoyRing::getNum() const {  return pCurrent->code;
}// 小孩离队
void BoyRing::disengage() { pivot->next = pCurrent->next;pCurrent = pivot;
}// 输出所有小孩
void BoyRing::printALL()const { vector<int> wins;int numinLine = 0;Boy* p = pCurrent;while(1) {wins.push_back(p->code);p = p->next;if (p == pCurrent) {break;}}sort(wins.begin(), wins.end());for (int win : wins) {cout << win<<" ";}cout << endl;
}// 析构函数
BoyRing::~BoyRing() { delete[] pBegin; // 释放空间
}

1221 表达式个数

题目:

Time Limit:1000MS  Memory Limit:32768K
Description:
1到N的序列: 1 2 3 4 5 ...N 每两个数之间插入 + 或 -,求其和恰为M的不同表达式个数。例如:N为7,M为0,则有: 1 + 2 - 3 + 4 - 5 - 6 + 7 = 0 1 + 2 - 3 - 4 + 5 + 6 - 7 = 0 1 - 2 + 3 + 4 - 5 + 6 - 7 = 0 1 - 2 - 3 - 4 - 5 + 6 + 7 = 0 所以N,M分别为7和0时,共有4种不同表达式。
Input:
输入中有若干行数据。每行中包含两个整数N(1≤ N ≤ 13),M(0≤ M ≤ N(N+1)/2)。M表示在1到N之间的各个间隙,使用 + 或 - 操作符,以构成表达式所计算的值。
Output:
对每个N和M,输出能够构成的表达式个数。如果没有,则应输出“NO”,每个结果占一行。
Sample Input:
7 0
3 2
2 1
Sample Output:
4
1
NO
Source:
qianneng

核心思想:

1. 用map存N、M、和对应的表达式个数num,后续再查表得结果。
2. 对于一个N值,怎么计算出其所有种表达式的值呢?方法是用二进制数来表示符号序列。/*
如当N=5:i 表示符号序列,是二进制的0000~1111,每一位代表一个符号,1是+,0是-:sum 刚开始是 1;j 是下一个要加的数,从 2 到 N,j 也用来计算二进制 i 右移的位数:sum + = (判断符号位)j;j 循环结束就求得某一个表达式的sum值了以N=5的时候,1+2+3+4-5为例:某趟循环i=1110:j从2到5:当j=2时,把i右移5-2=3位,得1(110),然后最低位与1相与,判断它是否是1,是1,那么sum+= j,否则sum+= -j;  */

流程:

// 预存结果
构建表,map里的每个元素存储3个变量:N、M、表达式个数num。N*100+M放在first,表达式个数放在second,每个N和M都有一个唯一的对应值。
遍历每个N:遍历每个M:遍历每种符号序列对应的表达式的结果:用一个循环计算表达式结果sum;若sum等于M,表达式个数num++;把N、M、num存入map中;
// 用户输入
用 find 找 N*100+M 的对应值;
输出,程序结束。

代码:

#include <iostream>
#include<map>
#include<algorithm>
using namespace std;int main() {map<int, int> ma;for (int N = 1; N <= 13; ++N) {for (int M = 0; M <= N * (N + 1) / 2; ++M) {int num = 0;for (int i = 0; i < 1 << N - 1; ++i) {int sum = 1;for (int j = 2; j <= N; ++j) {sum += (i >> N - j & 1 ? -j : j);}num += (sum == M);}if (num) {ma[N * 100 + M] = num;}}}for (int N, M; cin >> N >> M;) {if (ma.find(N * 100 + M) != ma.end()) {cout << ma[N * 100 + M] << endl;}else {cout << "No\n";}}
}for (int i = 1, numinLine = 0; i < n - w + 1; ++i) { // 循环执行以下步骤,直到达到获胜者数量x.countBy(m); //数m个小孩x.disengage();   //小孩离队}x.printALL();        //输出获胜者
}// 构造函数
BoyRing::BoyRing(int n) { if (n < 2) throw exception();  pBegin = new Boy[n]; // 按小孩数申请空间for (int i = 1; i <= n; i++) { // 初始化为环结构,小孩编号pBegin[i - 1].code = i;pBegin[i - 1].next = &pBegin[i % n];}pivot = pCurrent = &pBegin[n - 1]; // 指针赋初值
}// 数m个小孩
void BoyRing::countBy(int m) { for (int i = 1; i <= m; ++i) {pivot = pCurrent;pCurrent = pCurrent->next;}
}// 返回当前小孩编号
int BoyRing::getNum() const {  return pCurrent->code;
}// 小孩离队
void BoyRing::disengage() { pivot->next = pCurrent->next;pCurrent = pivot;
}// 输出所有小孩
void BoyRing::printALL()const { vector<int> wins;int numinLine = 0;Boy* p = pCurrent;while(1) {wins.push_back(p->code);p = p->next;if (p == pCurrent) {break;}}sort(wins.begin(), wins.end());for (int win : wins) {cout << win<<" ";}cout << endl;
}// 析构函数
BoyRing::~BoyRing() { delete[] pBegin; // 释放空间
}

1221 表达式个数

题目:

Time Limit:1000MS  Memory Limit:32768K
Description:
1到N的序列: 1 2 3 4 5 ...N 每两个数之间插入 + 或 -,求其和恰为M的不同表达式个数。例如:N为7,M为0,则有: 1 + 2 - 3 + 4 - 5 - 6 + 7 = 0 1 + 2 - 3 - 4 + 5 + 6 - 7 = 0 1 - 2 + 3 + 4 - 5 + 6 - 7 = 0 1 - 2 - 3 - 4 - 5 + 6 + 7 = 0 所以N,M分别为7和0时,共有4种不同表达式。
Input:
输入中有若干行数据。每行中包含两个整数N(1≤ N ≤ 13),M(0≤ M ≤ N(N+1)/2)。M表示在1到N之间的各个间隙,使用 + 或 - 操作符,以构成表达式所计算的值。
Output:
对每个N和M,输出能够构成的表达式个数。如果没有,则应输出“NO”,每个结果占一行。
Sample Input:
7 0
3 2
2 1
Sample Output:
4
1
NO
Source:
qianneng

核心思想:

1. 用map存N、M、和对应的表达式个数num,后续再查表得结果。
2. 对于一个N值,怎么计算出其所有种表达式的值呢?方法是用二进制数来表示符号序列。/*
如当N=5:i 表示符号序列,是二进制的0000~1111,每一位代表一个符号,1是+,0是-:sum 刚开始是 1;j 是下一个要加的数,从 2 到 N,j 也用来计算二进制 i 右移的位数:sum + = (判断符号位)j;j 循环结束就求得某一个表达式的sum值了以N=5的时候,1+2+3+4-5为例:某趟循环i=1110:j从2到5:当j=2时,把i右移5-2=3位,得1(110),然后最低位与1相与,判断它是否是1,是1,那么sum+= j,否则sum+= -j;  */

流程:

// 预存结果
构建表,map里的每个元素存储3个变量:N、M、表达式个数num。N*100+M放在first,表达式个数放在second,每个N和M都有一个唯一的对应值。
遍历每个N:遍历每个M:遍历每种符号序列对应的表达式的结果:用一个循环计算表达式结果sum;若sum等于M,表达式个数num++;把N、M、num存入map中;
// 用户输入
用 find 找 N*100+M 的对应值;
输出,程序结束。

代码:

#include <iostream>
#include<map>
#include<algorithm>
using namespace std;int main() {map<int, int> ma;for (int N = 1; N <= 13; ++N) {for (int M = 0; M <= N * (N + 1) / 2; ++M) {int num = 0;for (int i = 0; i < 1 << N - 1; ++i) {int sum = 1;for (int j = 2; j <= N; ++j) {sum += (i >> N - j & 1 ? -j : j);}num += (sum == M);}if (num) {ma[N * 100 + M] = num;}}}for (int N, M; cin >> N >> M;) {if (ma.find(N * 100 + M) != ma.end()) {cout << ma[N * 100 + M] << endl;}else {cout << "No\n";}}
}

【ACM】C++程序设计ACM题库总结相关推荐

  1. 《Python程序设计》题库(2)

    侵权联系我删除: [写在这里,方便右键百度搜索!] <Python程序设计>题库 填空题 Python安装扩展库常用的是_______工具.(pip) Python标准库math中用来计算 ...

  2. 计算机等级考试《二级Java语言程序设计》题库

    计算机等级考试<二级Java语言程序设计>题库 完整版:http://zgw.100xuexi.com/SubItem/IndexInfoDetail.aspx?id=e63f251c-3 ...

  3. 假设当年产值为100c语言答案,C语言程序设计试题题库含答案zdui.doc

    C语言程序设计试题题库含答案zdui 班号姓名 C语言 试 题 题号一二三四五六七八九十总分附加题分数 一.选择题:(20分,每题2分) 1.以下不正确的C语言标识符是( ). A. ABC B. a ...

  4. 假设当年产值为100c语言答案,C语言程序设计试题题库含答案zdui汇总.doc

    C语言程序设计试题题库含答案zdui汇总 班号姓名 C语言 试 题 题号一二三四五六七八九十总分附加题分数 一.选择题:(20分,每题2分) 1.以下不正确的C语言标识符是( ). A. ABC B. ...

  5. java程序设计清考_面向对象程序设计(Java)-题库

    <面向对象程序设计(Java)-题库>由会员分享,可在线阅读,更多相关<面向对象程序设计(Java)-题库(33页珍藏版)>请在金锄头文库上搜索. 1.面向对象程序设计 (ja ...

  6. c语言设计程序实现顺序冒泡_2019年9月全国计算机等级考试《二级C语言程序设计》题库...

    第一部分 历年真题 全国计算机等级考试<二级C语言程序设计>真题及详解(一) 全国计算机等级考试<二级C语言程序设计>真题及详解(二) 全国计算机等级考试<二级C语言程序 ...

  7. python程序设计教程题库_Python程序设计题库-查询

    Python程序设计题库-查询,将学生内部认知过程和外部行为结合起来,即方法.我国基础教育课程改革中的目标分类归纳为.布鲁姆的目标分类理论由组成.教学设计是依据教学理论学习理论和传播理论,运用系统科学 ...

  8. python中国大学慕课平台_中国大学MOOC(慕课)_Python程序设计_题库及答案

    中国的性目标质和我国卫生发展试述事业. 压下在常,大学最高温度可达水的. )的以(传热进行方式,慕课对流传导传递辐射.人口然属具有性和自生物属性.2捣点小车上装置在A固车安装激光接收.包括地缘群体,党 ...

  9. c语言程序设计开封电大,最新电大《C语言程序设计》题库及答案.docx

    <C语言程序设计>期末综合练习题 模拟试题一一.单选题1.在每个C语言程序中都必须包含有这样一个函数,该函数的函数名为(A).A. main B. MAIN C. name D. func ...

  10. 假设有python程序文件_《Python程序设计》题库

    一.填空题 第一章 基础知识 1 . Python 安装扩展库常用的是 _______ 工具.( pip ) 2 . Python 标准库 math 中用来计算平方根的函数是 __________ . ...

最新文章

  1. openshift介绍及centos7安装单节点openshift、Redhat安装openshift集群完全教程
  2. 利用Quartus设计4位同步二进制加法计数器
  3. DevOps案例研究:知人善任——Google敏捷核心文化
  4. JQuery .net WebService 参数必须一致
  5. 深度学习之卷积神经网络 GoogleNet
  6. idea加载lombok插件
  7. c#操作Xml(五)
  8. 第01期:salesforce开发环境的搭建
  9. MSDEV.EXE-应用程序错误解决办法(转)
  10. IEC 60335-1家用电器的安全标准及安规寿命检测设备
  11. AD18快速简单入门,画电路原理图以及PCB图
  12. vue实现简单的日历
  13. DEV GridView同时多列排序,附上排序列是实体解决右击没有排序箭头的问题
  14. 8.7.1. Declaration of Enumerated Types
  15. workerman php使用,workerman怎么用
  16. 位图字体生成工具 BMFont汉化版
  17. React中使用SVG文件显示成图片
  18. Android user版通过adb_enable开启adb 调试 不提示对话框
  19. ResNeSt: Split-Attention Networks(ResNet改进版本)
  20. geek_询问How-To Geek:如何监视带宽使用情况?

热门文章

  1. PHP中smart原则,制定目标时的SMART原则不包括什么
  2. flex blazeds java_flex blazeds连接java
  3. 倡导非盗版,自己常用的一些软件集锦
  4. nod32 破解的用户名密码
  5. 原神的天空岛服务器位置,原神天空岛服和世界树服数据互通吗
  6. html网页音乐手机播放,网页添加背景音乐代码,支持手机端的html5代码播放器
  7. Alexa技能开发从创建到发布
  8. JQuery blockUI 的使用方法
  9. cocos2dx基础篇(10)——编辑框之一CCTextFieldTTF
  10. 什么是WEBService,实现WEBService有哪些框架