0x01 P1009 [NOIP1998 普及组] 阶乘之和
这题要用高精度乘法和高精度加法,把每位数字单独存储到一个数组中,每个元素如果大于9再进位,以此类推。这题的乘法是半个高精度,一个是高精度数字,另一个是普通的int数,简单了一点。
不过如果两个都是高精度数的乘法,原理差不多,就是把这个一个高精度一个普通的做好多遍,然后全部加起来再进位就好了,以后有机会再写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<iostream> #include<math.h> #include<algorithm> using namespace std; int i,sum[1005]={0},one[1005]={0},n,j; int main(){ cin >> n; sum[0]=one[0]=1; for (i=2;i<=n;i++){ for (j=0;j<100;j++){ one[j]*=i; } for (j=0;j<100;j++) if(one[j]>9){ one[j+1] += one[j]/10; one[j]%=10; } for (j=0;j<100;j++){ sum[j]+=one[j]; if (sum[j]>9) { sum[j+1] += sum[j]/10; sum[j]%=10; } } } i = 100; while(i>=0 && sum[i]==0){ i--; } for (j=i;j>=0;j--){ printf("%d",sum[j]); } return 0; }
|
0x02 P1217 [USACO1.5] 回文质数 Prime Palindromes
sb题目,老是卡我时间。
先判断回文再判断质数,不然时间不够。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include<iostream> #include<math.h> #include<algorithm> using namespace std; bool zhi(int x){ for(int i=2;i*i<=x;i++) { if(x % i == 0){ return false; } } return true; } bool huiwen(int x){ int y=0; int temp=x; while(x>0){ y = y*10 + x%10; x /= 10; } if(temp==y){ return true; } return false; } int main(){ int a,b; cin >> a >> b; for(int i=a;i<=b;i++){ if(i==9989900){ break; } if(huiwen(i)&&zhi(i)){ cout << i <<"\n"; } } return 0; }
|
0x03 P1420 最长连号
超级超级简单的动态规划,把每次最长的连号存储起来,断了就重新计数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include<iostream> #include<math.h> #include<algorithm> using namespace std; int a[10005]; int dp[10005]; int main(){ int n,m = 0; cin >> n; for(int i=0;i<n;i++){ cin >> a[i]; dp[i] = 1; } for(int i=1;i<n;i++){ if(a[i]==a[i-1]+1){ dp[i] += dp[i-1]; } } for(int i=0;i<n;i++){ m = max(m,dp[i]); } cout << m; return 0; }
|
0x04 P3613 【深基15.例2】寄包柜
初次用容器vector和map解题,挺有意思的,map类似python的字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> #include<map> using namespace std; map<int,map<int,int>> V; vector<int> ans; int n,q,i,j,k,opcode=0; int main(){ cin >> n >> q; for(int t=1;t<=q;t++){ cin >> opcode >> i >> j; if(opcode==1){ cin >> k; V[i][j] = k; } if(opcode==2){ ans.push_back(V[i][j]); } } if(ans.size()!=0){ for(vector<int>::iterator it = ans.begin();it != ans.end(); it++){ cout << *it << '\n'; } } return 0; }
|
0x05 U264780 新生杯录取
题目大概的意思就是,再给定的很多数据里,挑选最小的几个然后排序。
由于限制了内存,先排序再取值很难实现,学习了堆排序的知识后,决定先取值再排序。
输入n个数据,然后排k,从小到大。
这里讲一下堆的结构,对于大堆,用完全二叉树的形式表示,他的任意一个节点的值总比他的左右孩子大,这里就隐含了一个信息,二叉树形式的堆的头结点的值是最大的,不管头结点的值怎么被修改,只要在此之后把堆维护一下,头结点的值仍然是最大的。用这个特性,我们在建立了k个元素的大堆后,之后每插入一个元素时先和头结点比较,如果更小就和头结点交换值,然后再维护一下,以此类推,最后堆内的k个元素必定是n个元素中最小的那几个,最后再堆排序一下输出。
知道思路后,关于堆,有建立堆,维护堆,堆排序三个操作,这里贴代码都有实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> using namespace std; int heap[105]; int n,k,temp; void swap(int heap[],int a, int b){ heap[0] = heap[a]; heap[a] = heap[b]; heap[b] = heap[0]; } void correctHeap(int heap[],int index, int len){ while(2 * index <= len){ int l = 2*index, r = 2*index+1 ; int maxIndex = l; if(r <= len && heap[r] > heap[l]){ maxIndex = r; } if(heap[index] >= heap[maxIndex]){ return; } swap(heap, index, maxIndex); index = maxIndex; } } void heapSort(int heap[], int len){ int s = len; while(s > 1){ swap(heap,1,s); s--; correctHeap(heap, 1, s); } } void heapCreate(int heap[], int len){ int index = len/2; while(index >= 0){ correctHeap(heap, index, len); index--; } } int main(){ std::ios_base::sync_with_stdio(false);std::cin.tie(0); cin >> n >> k; for(int i=1;i<=k;i++){ cin >> heap[i]; } heapCreate(heap,k); for(int i=1;i<=n-k;i++){ cin >> heap[104]; if(heap[104] < heap[1]){ swap(heap,104,1); correctHeap(heap,1,k); } } heapSort(heap,k); for(int i=1;i<=k;i++){ cout << heap[i] << " "; } return 0; }
|
堆的维护操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void correctHeap(int heap[],int index, int len){ while(2 * index <= len){ int l = 2*index, r = 2*index+1 ; int maxIndex = l; if(r <= len && heap[r] > heap[l]){ maxIndex = r; } if(heap[index] >= heap[maxIndex]){ return; } swap(heap, index, maxIndex); index = maxIndex; } }
|
堆的维护操作(这里以大堆为例子),其实就是让某个结点index和左右孩子结点比较,若双亲节点大则不用维护,若双亲节点小,交换双亲节点和值较大的那个孩子节点,之后有index 的节点继续作为双亲节点和他的孩子节点比较,直到叶子结点,或者双亲节点大。
堆的建立
1 2 3 4 5 6 7
| void heapCreate(int heap[], int len){ int index = len/2; while(index >= 0){ correctHeap(heap, index, len); index--; } }
|
堆的建立其实就是,把每个节点(叶子外)全都做一遍堆的维护,而且要自下而上(i—就可以实现)。这样做就能保证每个节点的左右孩子均比这个节点小。
堆排序
1 2 3 4 5 6 7 8
| void heapSort(int heap[], int len){ int s = len; while(s > 1){ swap(heap,1,s); s--; correctHeap(heap, 1, s); } }
|
堆排序,其实就是将堆顶元素一个一个取出来的操作,将堆顶元素和堆底元素交换,然后堆的大小减一,然后再把缩小后的堆维护一下,最后原先的那个堆,从堆底到堆顶,就是从大到小排序的数了,正着输出就是从小到大排序。
0x06 P1449 后缀表达式
这是一道用栈(stack)模拟算术的题,非常经典,故记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> #include<queue> #include<stack> using namespace std; char c; int num = 0; stack<int> sta; void run_code(char code){ int fir,sec; fir = sta.top(); sta.pop(); sec = sta.top(); sta.pop(); switch(code){ case '+': sec += fir; break; case '-': sec -= fir; break; case '*': sec *= fir; break; case '/': sec /= fir; break; default: break; } sta.push(sec); } int main(){ while(true){ cin >> c; if(c=='@'){ break; } else if(c>='0' && c<='9'){ num = 10*num + (c-'0'); } else if(c=='.'){ sta.push(num); num = 0; } else{ run_code(c); } } cout << sta.top(); return 0; }
|
0x07 P1996 约瑟夫问题
刚开始学C语言时碰到的难题,现在看来豁然开朗,记录一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> #include<queue> #include<stack> using namespace std; vector<int> ans,people(101,0); int n,m,cnt = 0,i=1; int main(){ cin >> n >> m; while(ans.size()!=n){ if(people[i]==0){ cnt++; } if(cnt == m){ cnt =0; people[i] = 1; ans.push_back(i); } i = (i%n) + 1; } for(vector<int>::iterator it=ans.begin();it!=ans.end();it++){ cout << *it << " "; } return 0; }
|
我用了模拟的方法,模拟这个过程进行。
0x08 P1160 队列安排
我真没想到我写的这一坨式能跑过,记录留念一下。
这题用链表查找,跑的内存真大,我以后看能不能优化一下这个思路。
内存爆满,有一说一,处理得不太好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> #include<list> #include<map> using namespace std; list<int> student; map<int,list<int>::iterator> id; list<int>::iterator it; int n,m,loc,stu_id;
int main(){ cin >> n; student.push_front(1); id[1] = student.begin(); for(int i=2;i<=n;i++){ cin >> stu_id >> loc; if(loc == 0){ id[i] = student.insert(id[stu_id],i); } if(loc == 1){ it = next(id[stu_id]); id[i] = student.insert(it,i); } } cin >> m; for(int i=1;i<=m;i++){ cin >> stu_id; if(*id[stu_id]!=0){ *id[stu_id] = 0; student.erase(id[stu_id]); } } for(it = student.begin();it!=student.end();it++){ cout << *it << " "; } id.clear(); map<int,list<int>::iterator>().swap(id); student.clear(); list<int>().swap(student); return 0; }
|
后来我写着写着发现,这题感觉根本就不用map这个东西,map容器id下标是int,完全用普通数组就可以胜任这个记录的工作。
后面看别人写的才发现insert操作会返回插入值位置的迭代器。。。。我还一直在搞什么it++,it—操作,搞得像个啥乱一样。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> #include<list> using namespace std; list<int> student; vector<list<int>::iterator> id; list<int>::iterator it; int n,m,loc,stu_id;
int main(){ cin >> n; id.resize(100005); student.push_front(1); id[1] = student.begin(); for(int i=2;i<=n;i++){ cin >> stu_id >> loc; if(loc == 0){ id[i] = student.insert(id[stu_id],i); } if(loc == 1){ it = next(id[stu_id]); id[i] = student.insert(it,i); } } cin >> m; for(int i=1;i<=m;i++){ cin >> stu_id; if(*id[stu_id]!=0){ *id[stu_id] = 0; student.erase(id[stu_id]); } } for(it = student.begin();it!=student.end();it++){ cout << *it << " "; } id.clear(); vector<list<int>::iterator>().swap(id); student.clear(); list<int>().swap(student); return 0; }
|
优化了一下,不使用map,而使用vector存取,内存消耗减少了一倍。
0x09 P1540 [NOIP2010 提高组] 机器翻译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include<iostream> #include<math.h> #include<algorithm> #include<vector> using namespace std; int m,n; int cnt = 0, word; vector<int> mem; int main(){ cin >> m >> n; mem.reserve(10000); for(int i=0;i<n;i++){ cin >> word; if(find(mem.begin(),mem.end(),word) == mem.end()){ mem.push_back(word); cnt++; } if(mem.size() > m){ mem.erase(mem.begin()); } } mem.clear(); vector<int>().swap(mem); cout << cnt; return 0; }
|
队列问题,不过需要常常遍历这个队列,所以不用queue而用vector代替了。