第二章:递归、分治(7.18)
递归
NC15173 The Biggest Water Problem
NC22164 更相减损术
NC208813 求逆序数
都是最基础的
NC207028 第k小数
记得读入优化(不然会T)
直接sort即可,但是可以通过这道题了解一下sort思想是什么
保证区间[l,mid]中的数都比[mid+1,r]中的小,再不停递归下去知道排序结束
#include<bits/stdc++.h> #define LL long long using namespace std; int a[5000003]; int read() { int f=1,x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } int find(int l,int r,int k) { if(l==r)return a[l]; int i=l,j=r; int mid=(l+r)>>1; int x=a[mid]; while(i<=j) { while(a[j]>x)j--; while(a[i]<x)i++; if(i<=j) { swap(a[i],a[j]);//交换达到排序作用 i++;j--; } } if(k<=j)return find(l,j,k); else if(k>=i)return find(i,r,k); else return a[k]; } int main() { int T=read(); while(T--) { int n=read(),k=read(); for(int i=1;i<=n;++i)a[i]=read(); printf("%d\n",find(1,n,k)); } }
NC201605 Bits
汉诺塔问题
NC16692 [NOIP2001]求先序排列
已知中序后序求先序
(牛客上有比较简洁的代码写法)
#include<bits/stdc++.h> using namespace std; void tree(string s1,string s2) { int len1=s1.size(); int len2=s2.size(); if(len1>0) { char ch=s2[len2-1]; //根节点 cout<<ch; //每次递归输出根节点 int pos=s1.find(ch); //在s1中找到ch出现的位置 //substr(start,len) tree(s1.substr(0,pos),s2.substr(0,pos)); //递归左子树 tree(s1.substr(pos+1),s2.substr(pos,len1-pos-1)); //递归右子树 } } int main() { string str1,str2; cin>>str1>>str2;//中序后序 tree(str1,str2); //构建左子树 return 0; }
已知先序后序求中序也是
分治
NC16660 [NOIP2004]FBI树
注意字符串怎么打会比较简洁
#include<bits/stdc++.h> using namespace std; int n; char s[1300]; char FBI(string s) { if(s.length()>1) { printf("%c",FBI(s.substr(0,s.length()/2))); printf("%c",FBI(s.substr(s.length()/2,s.length()/2))); } if (s==string(s.length(),'0')) return 'B';//all 0 if (s==string(s.length(),'1')) return 'I';//all 1 return 'F'; } int main() { scanf("%d",&n);n=pow(2,n); scanf("%s",s); printf("%c",FBI(s)); }
NC50999 表达式计算4
据说表达式计算用递归最不易出错
判断优先级和括号
#include<bits/stdc++.h> using namespace std; char s[40]; int number(int l,int r) { int ans=0; for(int i=l;i<=r;++i) ans=ans*10+s[i]-'0'; return ans; } int work(int l,int r) { int cnt=0; int add=-1,power=-1,mul=-1; for(int i=l;i<=r;++i) { if(s[i]=='(')cnt++; else if(s[i]==')')cnt--;//cnt记录括号 else if(!cnt) { switch(s[i]) { case '+': case '-': add=i; case '*': case '/': mul=i; case '^': power=i; } } } if(cnt>0&&s[l]=='(')//多余括号 return work(l+1,r); else if(cnt<0&&s[r]==')') return work(l,r-1); else if(!cnt&&add==-1&&mul==-1&&power==-1) { if(s[l]=='('&&s[r]==')')return work(l+1,r-1);//剩下的在式子里面 return number(l,r);//只剩下数字 } // else return 0; if(add!=-1) { if(s[add]=='+')return work(l,add-1)+work(add+1,r); else return work(l,add-1)-work(add+1,r); } if(mul!=-1) { if(s[mul]=='*')return work(l,mul-1)*work(mul+1,r); else return work(l,mul-1)/work(mul+1,r); } if(power!=-1)return pow(work(l,power-1),work(power+1,r)); } int main() { scanf("%s",s); printf("%d\n",work(0,strlen(s)-1)); }
NC23046 华华教月月做数学
快速幂和龟速乘
#include<bits/stdc++.h> #define LL long long using namespace std; LL gsc(LL a,LL b,LL p) { LL ans=0; while(b) { if(b&1)ans=(ans+a)%p; a=a*2%p; b>>=1; } return ans; } LL ksm(LL a,LL b,LL p) { LL ans=1; while(b) { if(b&1)ans=gsc(ans,a,p); a=gsc(a,a,p); b>>=1; } return ans; } int main() { int T;scanf("%d",&T); while(T--) { LL a,b,p;scanf("%lld%lld%lld",&a,&b,&p); printf("%lld\n",ksm(a,b,p)); } }