1,大整数加法:
链接:http://xmnd.openjudge.cn/ds201602/1/
分析:题意很简单,给两个大整数,让你求出他们两的和
其实Java中就有专门用于大整数、大浮点数的运算,有兴趣的了解一下,用起来很方便
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String str1 = sc.nextLine();
String str2 = sc.nextLine();
BigInteger x1 = new BigInteger(str1);
BigInteger x2 = new BigInteger(str2);
System.out.println(x1.add(x2));
}
sc.close();
}
}
好了,下面来谈如何用c++解决这个问题
很显然,长度为100的大整数long long也存不下(long long范围2 ^ 64, 小于10 ^ 100),所以考虑转换成字符串来求解
说一下大体思路,比如:
11123
321
这两个数用字符串的形式来进行运算的过程如下:
先翻转两个字符串,方便从最低位开始操作:
32111
123
加起来:
44411
倒序输出:
11444
这个还是挺好理解的吧,那么现在总结一下操作步骤:
翻转两个字符串,从低位到高位相加,注意进位,再倒过来输出就行了
思想有了,接下来就是代码实现:
(忽略using namespace std及以上的所有代码,这些都是为了我平时写代码方便个人喜好加上去的)
#pragma GCC diagnostic error "-std=c++11"
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII pair<int, int>
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
char a[205], b[205];//a, b数组保存的是输入
int x[205], y[205];//x, y数组保存的是字符串转换后的整数
//比如说a数组里面装的是123,实际上它们都是字符型的
//并不是所谓的一百二十三,要转换成整型才能进行相加得到正确的结果
int main()
{
scanf("%s %s", a, b);//输入两行字符串
int la = strlen(a);//strlen函数用于获取数组的长度,保存在la
int lb = strlen(b);//同上
int l = la > lb ? la : lb;//l保存的是两个数组中较长的一个的长度
reverse(a, a + la);//因为懒得手写让数组翻转的函数,直接用了reverse函数
//对于数组a, reverse(a + x, a + y)表示翻转区间[a[x], a[y-1]]
//那么reverse(a, a + la)就是翻转[a[0], a[la-1]]区间,也就是整个a数组
//因为数组下标从0开始嘛
reverse(b, b + lb);//同上
for(int i = 0; i < la; i++){//因为a,b里面保存的是字符,要转换成整数才能进行操作
x[i] = a[i] - '0';//这一行的意思是:减去字符0的ACSII码
//比如对于字符'7',我想获得它的整数值,就减去字符'0'就行了
//也就是 (char)'7' - (char)'0' = (int)7
}
for(int i = 0; i < lb; i++){
y[i] = b[i] - '0';
}//同上
//现在x, y数组里面装的就是整数表达了,开始进行相加操作
for(int i = 0; i < l; i++){
x[i] += y[i];//我准备把最后的结果直接保存在x数组里,就不需要另外开数组了
if(x[i] >= 10){//进位操作,如果加起来大于10,当前数就减去10,它的高一位加1
x[i+1]++;
x[i] -= 10;
}
}
while(x[l] == 0 && l >= 1){
l--;//处理有前导0的情况,比如我们现在得到的x是12000
//接下来倒序输出可不能输出00021,得把000去掉
}
for(int i = l; i >= 0; i--){//倒序输出
printf("%d", x[i]);
}
printf("\n");//换个行
return 0;
}
这是我这辈子写过的最详细的注释了QwQ...
2,约瑟夫问题
链接:http://xmnd.openjudge.cn/ds201602/2/
update:写了个简要解释:
关于这个做法的解释:
大致思路:每去掉一个人,都把当前位置的下一个人的编号设为0,得到一个新的约瑟夫环。后面的以此类推再来操作。
也就是每去掉一个人,问题的规模就减少一个人
那么很容易知道如何由旧约瑟夫环首元素下标(old)推出新下标(new)
new = (old – m) % n----------------------1式
(当然,这个结论的前提是首下标为0,所以这题最后有输出ans + 1操作)
那么:
old = (new + m) % n;------------------------2式
现在我们就知道了如何由旧的推出新的,也就是如何从规模小的约瑟夫环的解推出大的约瑟夫环的解了
(其实1式已经能递归求解了,但考虑到数据较大可能爆栈,还是决定转换为2式,这样递推就能求解了)
Code:
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII pair<int, int>
#define FAST ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
int main()
{
int n, m; scanf("%d %d", &n, &m);//输入
int ans = 0;//答案保存在ans里面(ans代表answer)
for(int i = 1; i <= n; i++){//因为每一轮出去一只猴子嘛,n轮下来就是答案(最后一只猴子的编号)了
ans = (ans + m) % i;
}
printf("%d\n", ans + 1)
return 0;
}
4:非递减有序集合合并
链接:http://xmnd.openjudge.cn/ds201602/4/
题目大意:给两个非递减的集合,求他们的并集,并且按非递减的顺序输出(并且每个元素具有集合元素的唯一性)
用STL里面的set即可完美解决,有兴趣自己了解:
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII pair<int, int>
#define FAST ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
int main()
{
int n, m; cin >> n >> m;
set<int> s;
for(int i = 1; i <= n + m; i++){
int x; cin >> x;
s.insert(x);
}
cout << s.size() << endl;
for(auto i : s){
cout << i << ' ';
}
cout << endl;
return 0;
}
接下来讲两个做法,一个O(n ^ 2)朴素做法,一个O(n)做法
由于数据范围较小,都可以过
第一种:直接将两个集合拼在一起,排个序,然后对于每一个元素,检查它是否与前一个相等,相等就不输出(为了满足唯一性)
比如一个已经合并好,排好序的集合
array: 1 2 2 3 4 5 5 5 7
vis : 1 1 0 1 1 1 0 0 1
标为0就不输出,标为1就输出
那么最后的结果就是
1 2 3 4 5 7
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII pair<int, int>
#define FAST ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
int a[600];
int vis[600];//vis数组的作用是标记一个元素是不是与它的上一个元素相等
int main()
{
int n, m; scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = n + 1; i <= n + m; i++) scanf("%d", &a[i]);//输入
for(int i = 1; i <= n + m; i++){//冒泡排序
for(int j = i; j <= n + m; j++){
if(a[i] > a[j]){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
int cnt = 1;//计数输出集合的大小,初始化为1因为加上了第一个
vis[1] = 1;//第一个是一定可以输出的
for(int i = 2; i <= n + m; i++){
if(a[i] == a[i-1]) vis[i] = 0;//相等就标为0
else vis[i] = 1, cnt++;//不相等标为1,计数器加一
}
printf("%d\n", cnt);//先输出集合大小,题目要求的
for(int i = 1; i <= n + m; i++){
if(vis[i] == 1) printf("%d ", a[i]);//如果开始的标记为1,就说明这个元素的前一个和它不相等,就可以输出
}
printf("\n");//换个行
return 0;
}
O(n)解法:
设置两个索引ia, ib,分别指向数组a, b的头元素,然后依次比较,谁的头元素比较小就放进答案数组,相等的话就不放,随便从两个选一个往后移一位,知道两个数组都遍历完为止
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII pair<int, int>
#define FAST ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;
int a[300], b[300];
int ans[600];
int main()
{
int n, m; scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= m; i++) scanf("%d", &b[i]);
a[n+1] = b[m+1] = 1000000000;//两个数组的末尾应该初始化为很大的一个数,方便后面的比较大小操作
int cnt = 0;//cnt记录答案数组的长度
int ia = 1, ib = 1;//ia,ib分别指向数组a,b的头元素
//输入的时候数组下标从1开始,所以ia,ib初始化为1
while(ia != (n + 1) || ib != (m + 1)){//当ia,ib没有同时指到末尾,即都指到末尾了,结束了,就跳出循环
if(a[ia] == b[ib]) ia++;//相等的话就不加,往后移一位(实际上这里是ib++也行)
else if(a[ia] < b[ib]){//数组a的头比数组b的头小,就把a的头放进答案数组,并且cnt++, ia++
ans[++cnt] = a[ia];
ia++;
}
else if(a[ia] > b[ib]){//数组b的头比数组a的头小,就把b的头放进答案数组,并且cnt++, ib++
ans[++cnt] = b[ib];
ib++;
}
}
printf("%d\n", cnt);//输出答案集合的大小
for(int i = 1; i <= cnt; i++){//输出答案集合的元素
printf("%d ", ans[i]);
}
printf("\n");//换个行
return 0;
}
over